package com.adealink.weparty.commonui.widget

import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.FrameLayout
import androidx.customview.widget.ViewDragHelper
import kotlin.math.max

class SlideLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    companion object {
        private const val DRAGGABLE_THRESHOLD = 150
    }

    var enableSlide = true
    var callback: Callback? = null
    var nestedScrollHandler: NestedScrollHandler? = null

    private val dragCallback by lazy {
        object : ViewDragHelper.Callback() {

            var originTop = 0
            var originLeft = 0
            var originBottom = 0
            var height = 0

            override fun tryCaptureView(child: View, pointerId: Int): Boolean {
                return child == getChildAt(0)
            }

            override fun onViewCaptured(capturedChild: View, activePointerId: Int) {
                originTop = capturedChild.top
                originLeft = capturedChild.left
                originBottom = capturedChild.bottom
                height = capturedChild.height
            }

            override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
                if (releasedChild.top - originTop < 10) {
                    // slide back
                    dragHelper.settleCapturedViewAt(originLeft, originTop)
                    invalidate()
                } else {
                    // slide out of screen
                    dragHelper.settleCapturedViewAt(originLeft, originBottom)
                    invalidate()
                    callback?.onSlideOut()
                }
            }

            override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
                return max(0, top)
            }

            override fun getViewVerticalDragRange(child: View): Int {
                return child.height
            }
        }
    }

    private val dragHelper: ViewDragHelper by lazy {
        ViewDragHelper.create(this, dragCallback).apply {
            setEdgeTrackingEnabled(ViewDragHelper.EDGE_TOP)
        }
    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        if (!enableSlide) return super.onInterceptTouchEvent(ev)

        // now only support slide up to down
        return if (ev.y < DRAGGABLE_THRESHOLD) {
            dragHelper.shouldInterceptTouchEvent(ev)
        } else if (nestedScrollHandler != null) {
            if (nestedScrollHandler?.canScrollVertically(-1) == true) {
                super.onInterceptTouchEvent(ev)
            } else {
                dragHelper.shouldInterceptTouchEvent(ev)
            }
        } else {
            super.onInterceptTouchEvent(ev)
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (!enableSlide) {
            super.onTouchEvent(event)
        }

        dragHelper.processTouchEvent(event)
        return true
    }

    override fun computeScroll() {
        super.computeScroll()
        if (dragHelper.continueSettling(true)) {
            invalidate()
        }
    }

    interface NestedScrollHandler {
        fun canScrollVertically(direction: Int): Boolean
        fun canScrollHorizontally(direction: Int): Boolean
    }

    interface Callback {
        fun onSlideOut()
    }

}