package com.adealink.weparty.commonui.ripple

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.Build
import android.util.AttributeSet
import android.view.View
import android.view.WindowManager
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import com.adealink.weparty.R
import com.adealink.weparty.commonui.ripple.lifecyle.RippleLifecycle
import com.adealink.weparty.commonui.ripple.lifecyle.RippleLifecycleAdapter
import java.util.LinkedList
import kotlin.math.min

/**
 * 水波纹扩散View
 * https://github.com/Leo199206/RippleView
 */
class RippleView : View {
    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        initAttributes(attrs)
        initPaint()
        if (isStart) {
            onStart()
        }
    }

    companion object {
        private const val MAX_ALPHA = 255
        private const val ALPHA_RANGE = 200
    }

    private var paint = Paint()

    //private var circleMaxRadius: Int = 0
    private var circleList: MutableList<RippleCircle> = LinkedList()
    private var isStart: Boolean = false
    private var isPause: Boolean = false

    private var showInnerCircle: Boolean = false

    //private var circleCenterX: Float = 0f
    //private var circleCenterY: Float = 0f
    private val rippleLifecycle: RippleLifecycle by lazy {
        RippleLifecycle(this)
    }


    @ColorInt
    private var circleColor: Int = Color.RED
    private var circleMinRadius: Float = 0f
    private var circleCount: Int = 5
    private var circleStyle: Paint.Style = Paint.Style.FILL
    private var speed: Float = 0.5f

    private var duration: Int = 200
    private var circleStrokeWidth: Float = 3f


    /**
     * 配置参数初始化
     * @param attrs AttributeSet?
     */
    private fun initAttributes(attrs: AttributeSet?) {
        val array = context.obtainStyledAttributes(attrs, R.styleable.RippleView)
        for (index in 0 until array.indexCount) {
            when (val indexedValue = array.getIndex(index)) {
                R.styleable.RippleView_ripple_circle_color -> {
                    circleColor = array.getColor(indexedValue, Color.RED)
                }

                R.styleable.RippleView_ripple_circle_min_radius -> {
                    circleMinRadius = array.getDimension(indexedValue, 0f)
                }

                R.styleable.RippleView_ripple_circle_count -> {
                    circleCount = array.getInt(indexedValue, 2)
                }

                R.styleable.RippleView_ripple_circle_duration -> {
                    duration = array.getInt(indexedValue, duration)
                }

                R.styleable.RippleView_ripple_circle_stroke_width -> {
                    circleStrokeWidth = array.getDimension(indexedValue, circleStrokeWidth)
                }

                R.styleable.RippleView_ripple_circle_style -> {
                    circleStyle = array.getInt(indexedValue, Paint.Style.FILL.ordinal).let {
                        if (it == Paint.Style.FILL.ordinal) {
                            Paint.Style.FILL
                        } else {
                            Paint.Style.STROKE
                        }
                    }
                }

                R.styleable.RippleView_ripple_circle_start -> {
                    isStart = array.getBoolean(indexedValue, false)
                }

                R.styleable.RippleView_ripple_show_inner_circle -> {
                    showInnerCircle = array.getBoolean(indexedValue, false)
                }

            }
        }
    }

    fun setRipple(
        color: Int,
        minRadius: Float,
        circleCount: Int,
        speed: Float,
        strokeWidth: Float
    ) {
        circleColor = color
        circleMinRadius = minRadius
        this.circleCount = circleCount
        this.speed = speed
        circleStrokeWidth = strokeWidth

        initPaint()
//        circleList.clear()
//        initCircle()
//        if (isStart) {
//            onStart()
//        }
    }


    /**
     * 圆形半径、透明度参数初始化
     */
    private fun initCircle() {
        //circleMaxRadius = (width / 2 - circleStrokeWidth).toInt()
//        circleCenterX = width / 2f
//        circleCenterY = height / 2f
        circleList.clear()
        circleList.add(RippleCircle(circleMinRadius, MAX_ALPHA))
    }

    private fun initSpeed() {
        val refreshRate = getDisplayRefreshRate(context)
        val refreshInterval = 1000f / refreshRate
        val refreshCount = duration / refreshInterval
        speed = (circleMaxRadius() - circleMinRadius) / refreshCount
    }

    private var refreshRate: Int = 0
    fun getDisplayRefreshRate(context: Context): Int {
        if (refreshRate != 0) {
            return refreshRate
        }
        val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            context.display.refreshRate
        } else {
            ContextCompat.getSystemService(
                context,
                WindowManager::class.java
            )?.defaultDisplay?.refreshRate ?: 60f
        }
        refreshRate = display.toInt()
        return refreshRate
    }

    private fun circleMaxRadius(): Int {
        return (width / 2 - circleStrokeWidth).toInt()
    }

    /**
     * 画笔初始化
     */
    private fun initPaint() {
        paint.style = circleStyle
        paint.strokeWidth = circleStrokeWidth
        paint.isDither = true
        paint.isAntiAlias = true
        paint.color = circleColor
    }


    /**
     * 测量控件尺寸
     * @param widthMeasureSpec Int
     * @param heightMeasureSpec Int
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val defaultWidth = 200
        var defaultHeight = 200
        val width = measureSize(widthMeasureSpec, defaultWidth)
        val height = measureSize(heightMeasureSpec, defaultHeight)
        val size = min(width, height)
        setMeasuredDimension(size, size)
    }

    /**
     * 测量尺寸
     *
     * @param measureSpec
     * @param defaultSize
     * @return
     */
    private fun measureSize(measureSpec: Int, defaultSize: Int): Int {
        var result: Int
        val mode = MeasureSpec.getMode(measureSpec)
        val size = MeasureSpec.getSize(measureSpec)
        if (mode == MeasureSpec.EXACTLY) {
            result = size
        } else {
            result = defaultSize
            if (mode == MeasureSpec.AT_MOST) {
                result = result.coerceAtMost(size)
            }
        }
        return result
    }


    /**
     * 尺寸变动回调
     * @param w Int
     * @param h Int
     * @param oldw Int
     * @param oldh Int
     */
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        initCircle()
        initSpeed()
    }

    /**
     * 视图绘制
     * @param canvas Canvas
     */
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        onDrawRippleCircle(canvas)
    }


    /**
     * 绘制水波纹
     * @param canvas Canvas
     */
    private fun onDrawRippleCircle(canvas: Canvas) {
        if (!isStart) {
            return
        }
        with(circleList.iterator()) {
            while (hasNext()) {
                next().also {
                    paint.alpha = it.alpha
                    canvas.drawCircle(
                        width / 2f,
                        //circleCenterX,
                        height / 2f,
                        //circleCenterY,
                        it.radius,
                        paint
                    )
                    it.radius += speed
                    if (it.radius > circleMaxRadius()) {
                        remove()
                    } else {
                        var length = (circleMaxRadius().toFloat() - circleMinRadius)
                        if (length <= 0) {
                            length = 1f
                        }
                        var currentLength = it.radius - circleMinRadius
                        if (currentLength <= 0) {
                            currentLength = 0f
                        }
                        val percent = currentLength / length
                        it.alpha =
                            (MAX_ALPHA - (percent) * ALPHA_RANGE).toInt()
                    }
                }
            }
            addNewRippleCircle()
        }
        if (showInnerCircle) {
            paint.alpha = 255
            canvas.drawCircle(
                width / 2f,
                //circleCenterX,
                height / 2f,
                //circleCenterY,
                circleMinRadius,
                paint
            )
        }
        postInvalidate()
    }


    /**
     * 添加新水波纹
     */
    private fun addNewRippleCircle() {
        if (circleList.size <= 0) {
            return
        }
        val add = if (circleCount > 1) {
            val minMeet = (circleMaxRadius() - circleMinRadius) / circleCount
            circleList.last().radius > (minMeet + circleMinRadius)
        } else {
            circleList.last().radius > (circleMaxRadius() - circleStrokeWidth)
        }
        if (add) {
            circleList.add(RippleCircle(circleMinRadius, MAX_ALPHA))
        }
    }


    /**
     * 绑定页面生命周期，自动进行资源释放
     * @param lifecycleOwner LifecycleOwner?
     */
    private fun bindLifecycle(lifecycleOwner: LifecycleOwner?) {
        lifecycleOwner
            ?.lifecycle
            ?.addObserver(RippleLifecycleAdapter(rippleLifecycle))
    }

    /**
     * 开始播放动画
     * @param lifecycleOwner LifecycleOwner?
     */
    fun onStart(lifecycleOwner: LifecycleOwner? = null) {
        bindLifecycle(lifecycleOwner)
        isStart = true
        circleList.add(RippleCircle(circleMinRadius, MAX_ALPHA))
        postInvalidate()
    }

    /**
     * 动画暂停后，恢复动画播放
     */
    fun onResume() {
        if (isPause) {
            isStart = true
            isPause = false
            postInvalidate()
        }
    }

    /**
     * 停止播放水波纹动画
     */
    fun onStop() {
        isPause = false
        isStart = false
        circleList.clear()
    }

    /**
     * 暂停水波纹动画播放
     */
    fun onPause() {
        if (isStart) {
            isPause = true
            isStart = false
        }
    }

}