package com.gh.gamecenter.common.view

import android.content.Context
import android.graphics.RectF
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewConfiguration
import com.github.piasy.biv.view.BigImageView
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sqrt

class DraggableBigImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : BigImageView(context, attrs, defStyle) {

    private var mInitScale: Float? = null
    private val mScaledTouchSlop by lazy { ViewConfiguration.get(context).scaledTouchSlop }
    private val mDismissEdge by lazy { height * 0.12 }
    private var mSingleTouch = true
    private var mFakeDragOffset = 0F
    private var mLastX = 0F
    private var mLastY = 0F
    private var mListener: DragListener? = null

    fun setDragListener(listener: DragListener) {
        mListener = listener
    }

    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
        when (event.actionMasked) {
            MotionEvent.ACTION_POINTER_DOWN -> {
                setSingleTouch(false)
                animate()
                    .translationX(0F).translationY(0F).scaleX(1F).scaleY(1F)
                    .setDuration(200).start()
            }
            MotionEvent.ACTION_DOWN -> if (mInitScale == null || mInitScale == 0F) mInitScale = ssiv?.scale
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> up()
            MotionEvent.ACTION_MOVE -> {
                val rectF = RectF()
                ssiv?.getPanRemaining(rectF)
                if (mSingleTouch && mInitScale != 0F && (rectF.top == 0f || rectF.bottom == 0f)) {
                    if (mLastX == 0F) mLastX = event.rawX
                    if (mLastY == 0F) mLastY = event.rawY
                    val offsetX = event.rawX - mLastX
                    val offsetY = event.rawY - mLastY
                    fakeDrag(offsetX, offsetY)
                }
            }
        }
        return super.dispatchTouchEvent(event)
    }

    private fun fakeDrag(offsetX: Float, offsetY: Float) {
        if (mFakeDragOffset == 0F) {
            // 大于60度才响应下拉消失
            if (abs(offsetY) / sqrt(3F) > abs(offsetX)) {
                if (offsetY > mScaledTouchSlop) {
                    mFakeDragOffset = mScaledTouchSlop.toFloat()
                } else if (offsetY < -mScaledTouchSlop) {
                    mFakeDragOffset = (-mScaledTouchSlop).toFloat()
                }
            }
        }
        if (mFakeDragOffset != 0F) {
            val fixedOffsetY = offsetY - mFakeDragOffset
            parent?.requestDisallowInterceptTouchEvent(true)
            val fraction = abs(max(-1F, min(1F, fixedOffsetY / height)))
            val fakeScale = 1 - min(0.4F, fraction)
            scaleX = fakeScale
            scaleY = fakeScale
            translationY = fixedOffsetY
            translationX = offsetX / 2
            mListener?.onDrag(this, fraction)
        }
    }

    private fun up() {
        parent?.requestDisallowInterceptTouchEvent(false)
        setSingleTouch(true)
        mFakeDragOffset = 0F
        mLastX = 0F
        mLastY = 0F

        if (abs(translationY) > mDismissEdge) {
            mListener?.onRelease(this, scaleX)
        } else {
            val offsetY = translationY
            val fraction = min(1F, offsetY / height)
            mListener?.onRestore(this, fraction)

            animate().translationX(0F)
                .translationY(0F)
                .scaleX(1F)
                .scaleY(1F)
                .setDuration(200).start()
        }
    }

    fun isDragging(): Boolean {
        return mFakeDragOffset != 0F
    }

    private fun setSingleTouch(value: Boolean) {
        mSingleTouch = value
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        animate().cancel()
    }

    interface DragListener {
        fun onDrag(draggableBigImageView: DraggableBigImageView, fraction: Float)
        fun onRelease(draggableBigImageView: DraggableBigImageView, scale: Float)
        fun onRestore(draggableBigImageView: DraggableBigImageView, fraction: Float)
    }

}