package com.adealink.weparty.commonui.util

import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.view.ViewGroup
import androidx.core.view.children
import com.adealink.frame.base.fastLazy
import com.adealink.frame.log.Log
import com.adealink.frame.util.DisplayUtil
import com.adealink.frame.util.isTouchPointInView
import kotlin.math.abs

/**
 * 这个工具可以使任何一个view进行拖动。
 */

enum class DragDirection {
    HORIZONTAL, //仅水平方向移动
    VERTICAL, //仅垂直方向移动
    FREE //自由移动
}

object DragViewUtil {

    const val TAG = "DragViewUtil"

    interface DragListener {
        fun onDragStart()
    }

    /**
     * 拖动View方法
     *
     * @param v     view
     * @param delay 延迟
     */
    @JvmOverloads
    fun registerDragAction(
        v: View,
        direction: DragDirection,
        listener: DragListener? = null
    ): TouchListener {
        v.isClickable = true
        val touchListener = TouchListener(v, direction, listener)
        v.setOnTouchListener(touchListener)
        return touchListener
    }

    class TouchListener(
        val targetView: View,
        private val direction: DragDirection,
        private val listener: DragListener? = null
    ) :
        View.OnTouchListener {
        private var downX = 0f
        private var downY = 0f
        private var downRawX = 0f
        private var downRawY = 0f

        private var downTime: Long = 0
        private var isMove = false
        private var canDrag = false
        private var marginLeft = 0f
        private var marginTop = 0f
        private var marginRight = 0f
        private var marginBottom = 0f
        private var touchSlop: Int = 0

        init {
            touchSlop = ViewConfiguration.get(targetView.context).scaledPagingTouchSlop
        }

        override fun onTouch(v: View, event: MotionEvent): Boolean {
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    downX = event.x
                    downY = event.y
                    downRawX = event.rawX
                    downRawY = event.rawY
                    isMove = false
                    downTime = System.currentTimeMillis()
                    canDrag = true
                    Log.d(TAG, "onDragStart")
                    listener?.onDragStart()
                }

                MotionEvent.ACTION_MOVE -> {
                    val xDistance = event.x - downX
                    val yDistance = event.y - downY
                    Log.d(TAG, "onDragMove, xD:${xDistance},yD:${yDistance}")
                    if (xDistance != 0f && yDistance != 0f) {
                        updateViewLayout(v, xDistance, yDistance)
                        isMove = true
                    }
                }

                MotionEvent.ACTION_UP -> {
                    if (abs(downRawX - event.rawX) < touchSlop && abs(downRawY - event.rawY) < touchSlop) {
                        Log.d(TAG, "onActionUp(ViewGroup.findClickableChild), performClick")
                        findClickableChild(targetView, event)?.performClick()
                    }
                }

                else -> {}
            }
            return true
        }

        private fun findClickableChild(view: View, event: MotionEvent): View? {
            if (view is ViewGroup) {
                for (child in view.children) {
                    val clickView = findClickableChild(child, event)
                    if (clickView != null) {
                        return clickView
                    }
                }
            }
            if (view.isClickable && view.hasOnClickListeners()) {
                if (isTouchPointInView(view, event.rawX.toInt(), event.rawY.toInt())) {
                    return view
                }
            }
            return null
        }

        private val screenW by fastLazy { DisplayUtil.getScreenWidth() }
        private val screenH by fastLazy { DisplayUtil.getScreenHeight() }

        private fun updateViewLayout(v: View, xDistance: Float, yDistance: Float) {
            var x = v.x
            var y = v.y

            when (direction) {
                DragDirection.VERTICAL -> {
                    y = v.y + yDistance
                    y = marginTop.coerceAtLeast(y)
                    y = (screenH - v.height - marginBottom).coerceAtMost(y)
                }

                DragDirection.HORIZONTAL -> {
                    x = v.x + xDistance
                    if (v.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                        x = marginRight.coerceAtLeast(x)
                        x = (screenW - v.width - marginLeft).coerceAtMost(x)
                    } else {
                        x = marginLeft.coerceAtLeast(x)
                        x = (screenW - v.width - marginRight).coerceAtMost(x)
                    }
                }

                DragDirection.FREE -> {
                    x = v.x + xDistance
                    y = v.y + yDistance
                    if (v.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                        x = marginRight.coerceAtLeast(x)
                        x = (screenW - v.width - marginLeft).coerceAtMost(x)
                    } else {
                        x = marginLeft.coerceAtLeast(x)
                        x = (screenW - v.width - marginRight).coerceAtMost(x)
                    }
                    y = marginTop.coerceAtLeast(y)
                    y = (screenH - v.height - marginBottom).coerceAtMost(y)
                }
            }

            Log.d(TAG, "updateViewLayout, x:${x},y:${y}")
            v.x = x
            v.y = y
        }

        /**
         * 设置边距
         */
        fun setMargins(left: Float, top: Float, right: Float, bottom: Float) {
            this.marginLeft = left
            this.marginTop = top
            this.marginRight = right
            this.marginBottom = bottom
        }
    }
}