package com.adealink.weparty.commonui.widget

import android.animation.Animator
import android.animation.Animator.AnimatorListener
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Path
import android.graphics.PathMeasure
import android.graphics.PointF
import android.util.AttributeSet
import android.view.View
import android.view.animation.Interpolator
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.adealink.frame.log.Log

/**
 * 收集路径动效
 * 支持多条路径
 */
class CollectPathAnimView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {

    private var viewSize = 200
    private var collectViewCreator: CollectViewCreator? = null

    //总共多少个动画视图
    private var collectCount: Int = DEFAULT_CURRENCY_COUNT

    //同一时间显示多少个动画视图
    private var maxAnimCount: Int = MAX_CURRENCY_COLLECTING

    //一个动画视图完成路径动画的时长.
    //Tips: 总时长 = animDuration + (collectCount - 1) * animOffsetDuration
    private var animDuration: Long = DEFAULT_ANIM_DURATION
    private var animOffsetDuration: Long = DEFAULT_ANIM_OFFSET_DURATION

    private var animListener: ICollectAnimListener? = null
    private var paths: List<PointF>? = null
    private val animPath = Path()
    private var animSet = mutableSetOf<AnimatorSet>()
    private var interpolator: Interpolator = DEFAULT_INTERPOLATOR

    fun setPath(vararg positions: PointF) {
//        this.paths = positions.map {
//            PointF(
//                it.x - viewSize,
//                it.y - viewSize
//            )
//        }
        this.paths = positions.toList()
    }

    fun setInterpolator(interpolator: Interpolator) {
        this.interpolator = interpolator
    }

    fun setCollectCount(count: Int) {
        this.collectCount = count
    }

    fun setMaxAnimCount(count: Int) {
        this.maxAnimCount = count
    }

    fun setAnimListener(listener: ICollectAnimListener?) {
        animListener = listener
    }

    fun setCollectViewCreator(creator: CollectViewCreator, viewSize: Int) {
        this.viewSize = viewSize
        this.collectViewCreator = creator
    }

    fun setDuration(duration: Long) {
        this.animDuration = duration
    }

    fun setOffsetDuration(duration: Long) {
        this.animOffsetDuration = duration
    }

    fun startAnim() {
        val paths = this.paths
        if (paths.isNullOrEmpty()) {
            Log.d(TAG, "startAnim return, for paths is null or empty")
            return
        }
        val viewCreator = collectViewCreator
        if (viewCreator == null) {
            Log.d(TAG, "startAnim return, for viewCreator is null")
            return
        }
        if (animDuration <= 0) {
            Log.d(TAG, "startAnim return, for duration <= 0")
            return
        }
        playInner(viewCreator, paths)
    }

    @SuppressLint("Recycle")
    private fun playInner(viewCreator: CollectViewCreator, paths: List<PointF>) {
        stopAnim()
        //创建视图
        if (childCount != maxAnimCount) {
            inflateCollectingView(viewCreator)
        }
        //创建路径动画
        animPath.reset()
        for ((index, pos) in paths.withIndex()) {
            if (index == 0) {
                animPath.moveTo(pos.x, pos.y)
            } else {
                animPath.lineTo(pos.x, pos.y)
            }
        }
        val animPathMeasure = PathMeasure(animPath, false)

        //启动路径动画
        for (i in 0 until collectCount) {
            val delay = i * animOffsetDuration
            Log.d(TAG, "playInner, i:$i, delay:$delay")
            val child = getChildAt(i % childCount) ?: continue
            child.postDelayed(
                {
                    playPathAnim(child, animPathMeasure, i)
                },
                delay
            )
        }
        postDelayed({
            animListener?.onFinish()
        }, collectCount * animOffsetDuration + animDuration)
    }

    private fun playPathAnim(view: View, animPathMeasure: PathMeasure, position: Int) {
        Log.d(TAG, "playInner, i:$position$")
        var distance = 0f
        val pos = floatArrayOf(0f, 0f)
        val valueAnimator = ValueAnimator.ofFloat(0f, 1f)
        valueAnimator.duration = animDuration
        valueAnimator.interpolator = interpolator
        valueAnimator.addListener(object : AnimatorListener {
            override fun onAnimationStart(animation: Animator) {
                view.visibility = View.VISIBLE
                animListener?.onStart(position)
            }

            override fun onAnimationEnd(animation: Animator) {
                view.visibility = View.GONE
                animListener?.onEnd(position)
            }

            override fun onAnimationCancel(animation: Animator) {
            }

            override fun onAnimationRepeat(animation: Animator) {
            }

        })

        valueAnimator.addUpdateListener {
            distance = it.animatedValue as Float
            animPathMeasure.getPosTan(distance * animPathMeasure.length, pos, null)
            view.x = pos[0] - viewSize / 2
            view.y = pos[1] - viewSize / 2
            animListener?.onUpdate(view, position, distance)
        }
        valueAnimator.start()
    }

    private fun stopAnim() {
        if (animSet.isEmpty() || childCount == 0) {
            return
        }
        animSet.forEach {
            it.cancel()
        }
        animSet.clear()
        removeAllViews()
    }

    private fun inflateCollectingView(viewCreator: CollectViewCreator) {
        for (i in 0 until maxAnimCount) {
            val itemView = viewCreator.createCollectView(context)
            addView(itemView)
            itemView.updateLayoutParams<LayoutParams> {
                width = viewSize
                height = viewSize
            }
            itemView.visibility = View.GONE
        }
    }

    interface ICollectAnimListener {
        fun onStart(position: Int)

        fun onUpdate(view: View, position: Int, percent: Float)

        fun onEnd(position: Int)

        fun onFinish()
    }

    interface CollectViewCreator {
        fun createCollectView(context: Context): View
    }


    companion object {
        private const val TAG = "CollectCurrencyAnimView"

        private const val DEFAULT_CURRENCY_COUNT = 10
        private const val DEFAULT_COLLECT_DELAY = 80L
        private const val DEFAULT_ANIM_DURATION = 2400L //单个动画飞过去的时间
        private const val DEFAULT_ANIM_OFFSET_DURATION = 250L //动画间隔

        private const val MAX_CURRENCY_COLLECTING = 10 //有多少个在同一时间收集

        private val DEFAULT_INTERPOLATOR = object : Interpolator {

            private val percent = 90f  //范围(0~100)
            private val finishInput = percent / 100f

            override fun getInterpolation(input: Float): Float {
                return if (input < finishInput) {
                    ((Math.cos((input * 100f / percent + 1) * Math.PI) / 2.0f) + 0.5f).toFloat()
                } else {
                    1f
                }
            }
        }
    }

}