package cn.learningpad.oraltrainer.sdk

import android.content.Context
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ViewConfiguration
import android.widget.FrameLayout
import androidx.media3.ui.PlayerView
import kotlin.math.abs

class OralTrainerPlayerView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : FrameLayout(context, attrs, defStyleAttr) {
    val playerView: PlayerView = PlayerView(context).apply {
        useController = false
        layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
    }

    private var controller: OralTrainerController? = null
    private var gestureControls = GestureControlsConfig()
    private val density = resources.displayMetrics.density
    private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
    private val longPressTimeoutMs = ViewConfiguration.getLongPressTimeout().toLong()
    private var longPressStartX = 0f
    private var longPressStartY = 0f
    private var longPressActive = false
    private var speedBeforeLongPress: Float? = null
    private var verticalSwipeListener: ((isSwipeUp: Boolean) -> Unit)? = null

    private val longPressSpeedRunnable = Runnable {
        val activeController = controller ?: return@Runnable
        if (!gestureControls.enabled || !gestureControls.longPressAdjustsSpeed || width <= 0) {
            return@Runnable
        }
        longPressActive = true
        speedBeforeLongPress = activeController.snapshot().playbackSpeed
        activeController.setPlaybackSpeed(speedForTouchX(longPressStartX))
        activeController.dispatchGesture(GestureEvent(GestureKind.LONG_PRESS_SPEED))
    }

    private val gestureDetector = GestureDetector(
        context,
        object : GestureDetector.SimpleOnGestureListener() {
            override fun onDown(e: MotionEvent): Boolean = true

            override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
                val activeController = controller ?: return false
                if (!gestureControls.enabled || !gestureControls.tapTogglesPlayPause) {
                    return false
                }
                activeController.togglePlayPause()
                activeController.dispatchGesture(GestureEvent(GestureKind.SINGLE_TAP))
                return true
            }

            override fun onFling(
                e1: MotionEvent?,
                e2: MotionEvent,
                velocityX: Float,
                velocityY: Float,
            ): Boolean {
                val activeController = controller ?: return false
                val start = e1 ?: return false
                if (!gestureControls.enabled) {
                    return false
                }
                val dx = e2.x - start.x
                val dy = e2.y - start.y
                val minDistancePx = gestureControls.minSwipeDistanceDp * density
                val minVelocityPx = gestureControls.minSwipeVelocityDpPerSecond * density
                if (abs(dy) > minDistancePx && abs(dy) > abs(dx) && abs(velocityY) >= minVelocityPx) {
                    val isSwipeUp = dy < 0
                    verticalSwipeListener?.invoke(isSwipeUp)
                    return true
                }
                if (abs(dx) < abs(dy) || abs(dx) < minDistancePx || abs(velocityX) < minVelocityPx) {
                    return false
                }
                val isRight = dx > 0
                val action = if (isRight) {
                    gestureControls.rightSwipeAction
                } else {
                    gestureControls.leftSwipeAction
                }
                activeController.performSwipeAction(action)
                activeController.dispatchGesture(
                    GestureEvent(
                        kind = if (isRight) GestureKind.SWIPE_RIGHT else GestureKind.SWIPE_LEFT,
                        action = action,
                    )
                )
                return true
            }
        }
    )

    init {
        addView(playerView)
        isClickable = true
        isFocusable = true
    }

    fun bind(controller: OralTrainerController) {
        this.controller = controller
        this.gestureControls = controller.config.gestureControls
        playerView.player = controller.player
    }

    fun unbind() {
        playerView.player = null
        controller = null
    }

    fun updateGestureControls(config: GestureControlsConfig) {
        gestureControls = config
    }

    fun setVerticalSwipeListener(listener: ((isSwipeUp: Boolean) -> Unit)?) {
        verticalSwipeListener = listener
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        if (handleLongPressSpeed(ev)) {
            return true
        }
        return gestureDetector.onTouchEvent(ev) || super.dispatchTouchEvent(ev)
    }

    override fun onDetachedFromWindow() {
        cancelLongPressSpeed(restoreSpeed = true)
        super.onDetachedFromWindow()
    }

    private fun handleLongPressSpeed(event: MotionEvent): Boolean {
        if (!gestureControls.enabled || !gestureControls.longPressAdjustsSpeed) {
            return false
        }
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                longPressStartX = event.x
                longPressStartY = event.y
                longPressActive = false
                speedBeforeLongPress = null
                removeCallbacks(longPressSpeedRunnable)
                postDelayed(longPressSpeedRunnable, longPressTimeoutMs)
                return false
            }

            MotionEvent.ACTION_MOVE -> {
                if (longPressActive) {
                    controller?.setPlaybackSpeed(speedForTouchX(event.x))
                    return true
                }
                val dx = abs(event.x - longPressStartX)
                val dy = abs(event.y - longPressStartY)
                if (dx > touchSlop || dy > touchSlop) {
                    removeCallbacks(longPressSpeedRunnable)
                }
                return false
            }

            MotionEvent.ACTION_UP,
            MotionEvent.ACTION_CANCEL -> {
                val wasActive = longPressActive
                cancelLongPressSpeed(restoreSpeed = wasActive)
                return wasActive
            }
        }
        return false
    }

    private fun cancelLongPressSpeed(restoreSpeed: Boolean) {
        removeCallbacks(longPressSpeedRunnable)
        if (restoreSpeed) {
            controller?.setPlaybackSpeed(speedBeforeLongPress ?: 1f)
        }
        longPressActive = false
        speedBeforeLongPress = null
    }

    private fun speedForTouchX(x: Float): Float {
        val center = width / 2f
        val distanceRatio = if (center <= 0f) 0f else abs(x - center) / center
        val farFromCenter = distanceRatio >= 0.5f
        return if (x < center) {
            if (farFromCenter) gestureControls.longPressSlowerSpeed else gestureControls.longPressSlowSpeed
        } else {
            if (farFromCenter) gestureControls.longPressFasterSpeed else gestureControls.longPressFastSpeed
        }
    }
}
