package com.adealink.weparty.commonui.drawabletoolbox

import android.animation.ValueAnimator
import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.RectF
import android.graphics.SweepGradient
import android.graphics.drawable.Drawable
import android.view.animation.LinearInterpolator
import com.adealink.frame.log.Log
import com.adealink.weparty.commonui.ext.dpf

//边框渐变流体动画
//参考: https://blog.csdn.net/willway_wang/article/details/126698866
class FluidColorfulFrameDrawable : Drawable() {
    companion object {
        private const val TAG = "FluidColorfulFrameDrawable"

        private val DEFAULT_RADIUS: Float = 10.dpf()
        private val DEFAULT_STROKE_WIDTH: Float = 5.dpf()

        private const val ANIM_DURATION = 3000L
    }

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private lateinit var bounds: RectF
    private val rectF = RectF()
    private var radius = DEFAULT_RADIUS
    private var strokeWidth = DEFAULT_STROKE_WIDTH
    private var colors = intArrayOf()
    private var positions = floatArrayOf()
    private var animDuration = ANIM_DURATION

    private var frameLength = 0f //周长
    private var frameAnimDegreeStep = 0f //动画

    private val mtx = Matrix()
    var degree: Float = 0f
        set(value) {
            field = value
            invalidateSelf()
        }

    init {
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = strokeWidth
    }

    fun setRadius(radius: Float) {
        this.radius = radius
    }

    fun setStrokeWidth(strokeWidth: Float) {
        this.strokeWidth = strokeWidth
        paint.strokeWidth = strokeWidth
    }

    fun setColorsAndPosition(colors: IntArray, positions: FloatArray) {
        if (colors.size > positions.size) {
            throw IllegalArgumentException("setColorsAndPosition fail, for colors.size > positions.size")
        }
        this.colors = colors
        this.positions = positions
    }

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

    override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
        super.setBounds(left, top, right, bottom)
        bounds = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
        rectF.left = strokeWidth / 2
        rectF.top = strokeWidth / 2
        rectF.right = bounds.width() - strokeWidth / 2
        rectF.bottom = bounds.height() - strokeWidth / 2
        paint.shader = SweepGradient(bounds.centerX(), bounds.centerY(), colors, positions)

        frameLength = (bounds.width() + bounds.height()) * 2
        frameAnimDegreeStep = frameLength / ANIM_DURATION
    }

    override fun draw(canvas: Canvas) {
        mtx.reset()
        mtx.setRotate(degree, bounds.centerX(), bounds.centerY())
        (paint.shader as SweepGradient).setLocalMatrix(mtx)
        canvas.drawRoundRect(rectF, radius, radius, paint)
    }

    override fun setAlpha(alpha: Int) {
        paint.alpha = alpha
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        paint.colorFilter = colorFilter
    }

    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }

    private var fluidAnim: ValueAnimator? = null

    fun startFluid() {
        Log.d(TAG, "startFluid")
        fluidAnim = ValueAnimator().apply {
            setIntValues(0, frameLength.toInt())
            this.duration = animDuration
            this.repeatCount = ValueAnimator.INFINITE
            this.interpolator = LinearInterpolator()
            this.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
                override fun onAnimationUpdate(animation: ValueAnimator) {
                    val targetLength = (animation.animatedValue as? Int) ?: return
                    val targetDegree = (targetLength.toFloat() / frameLength) * 360f
                    degree = targetDegree
                }
            })
            start()
        }
    }

    fun isFluiding(): Boolean {
        return fluidAnim != null && fluidAnim?.isRunning == true
    }

    fun isFluidStarted(): Boolean {
        return fluidAnim != null && fluidAnim?.isStarted == true
    }

    fun cancelFluid() {
        Log.d(TAG, "cancelFluid")
        fluidAnim?.cancel()
        fluidAnim = null
    }

    fun resumeFluid() {
        Log.d(TAG, "resumeFluid")
        if (isFluidStarted()) {
            fluidAnim?.start()
        }
    }
}