package com.develop.step.widgets

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.sqrt

class RingControlView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    private val fillPath = Path()
    private val stubPath = Path()
    private val ringPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val extraPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val ringStrokeWidth = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP, 13f, context.resources.displayMetrics
    )
    private val controlDotRadius = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP, 14f, context.resources.displayMetrics
    )
    private val ringPadding = (controlDotRadius * 2 - ringStrokeWidth) / 2
    private var progress: Float = 0.5f
    private var controlling = false
    private var controlDotX = 0.0
    private var controlDotY = 0.0

    var onRingViewListener: OnRingViewListener? = null
    init {
        ringPaint.color = 0xffE60012.toInt()
        ringPaint.style = Paint.Style.STROKE
        ringPaint.strokeCap = Paint.Cap.ROUND
        ringPaint.strokeWidth = ringStrokeWidth
    }

    private var minPro = 0f
    private var maxPro = 100f
    private var isCanTouch = true

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        stubPath.reset()
        stubPath.addArc(
            ringStrokeWidth / 2 + ringPadding,
            ringStrokeWidth / 2 + ringPadding,
            w.toFloat() - ringStrokeWidth / 2 - ringPadding,
            h.toFloat() - ringStrokeWidth / 2 - ringPadding,
            -240f, 300f
        )
        rebuildFillData(progress)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        extraPaint.color = 0x60ffffff
        val radius = width / 2f - ringStrokeWidth - ringPadding
        canvas.drawCircle(width / 2f, height / 2f, radius, extraPaint)
        ringPaint.color = 0xffffffff.toInt()
        canvas.drawPath(stubPath, ringPaint)
        ringPaint.color = 0xffE60012.toInt()
        canvas.drawPath(fillPath, ringPaint)
        extraPaint.color = 0xffFFA627.toInt()

        // -150 ~ 150
        val angle = 300.0 * progress - 150.0
        val dotRadius = width / 2 - ringPadding - ringStrokeWidth / 2
        val dotX = sin(Math.toRadians(angle)) * dotRadius + width / 2
        val dotY = height / 2 - cos(Math.toRadians(angle)) * dotRadius
        canvas.drawCircle(
            dotX.toFloat(), dotY.toFloat(), controlDotRadius, extraPaint
        )
    }

    private fun rebuildFillData(percent: Float) {
        val w = width
        val h = height
        fillPath.reset()
        fillPath.addArc(
            ringStrokeWidth / 2 + ringPadding,
            ringStrokeWidth / 2 + ringPadding,
            w.toFloat() - ringStrokeWidth / 2 - ringPadding,
            h.toFloat() - ringStrokeWidth / 2 - ringPadding,
            -240f, percent * 300f
        )
        // -150 ~ 150
        val angle = 300.0 * percent - 150.0
        val dotRadius = width / 2 - ringPadding - ringStrokeWidth / 2
        controlDotX = sin(Math.toRadians(angle)) * dotRadius + width / 2
        controlDotY = height / 2 - cos(Math.toRadians(angle)) * dotRadius
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (!isCanTouch) return false
        val moveX = event.x
        val moveY = event.y
        val distance = sqrt(
            (controlDotX - moveX) * (controlDotX - moveX) + (controlDotY - moveY) * (controlDotY - moveY)
        )
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (distance > 60) {
                    return super.onTouchEvent(event)
                }
                controlling = true
                calculateCurrentPercent(moveX, moveY)
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                if (controlling) {
                    calculateCurrentPercent(moveX, moveY)
                    return true
                }
            }
            MotionEvent.ACTION_CANCEL,
            MotionEvent.ACTION_UP -> {
                if (controlling) {
                    controlling = false
                    calculateCurrentPercent(moveX, moveY)
                    return true
                }
            }
        }
        return super.onTouchEvent(event)
    }

    private fun calculateCurrentPercent(moveX: Float, moveY: Float) {
        val distance = sqrt(
            (width / 2.0 - moveX) * (width / 2.0 - moveX) + (height / 2.0 - moveY) * (height / 2.0 - moveY)
        )
        val px = width / 2f - moveX
        val degree = Math.acos(px / distance)
        var angle = Math.toDegrees(degree)
        if (moveY > height / 2) {
            if (moveX < width / 2) {
                angle = -angle
            } else {
                angle = 360 - angle
            }
        }
        val percent = (angle + 60f) / 300f
        if (abs(percent - this.progress) > 0.2f) {
            return
        }
        setProgress(percent.toFloat())
        onRingViewListener?.onProgressChange((progress * (maxPro - minPro) + minPro).toInt())
    }

    private fun setProgress(progress: Float) {
        if (progress > 1) {
            this.progress = 1f
        } else if (progress < 0) {
            this.progress = 0f
        } else {
            this.progress = progress
        }
        if (width > 0) {
            rebuildFillData(this.progress)
        }
        postInvalidate()
    }

    fun updateProgress(value: Int) {
        progress = value / maxPro
        setProgress(progress)
    }

    /**
     * 设置范围默认0-100
     *
     */
    fun setRange(min: Float, max: Float) {
        minPro = min
        maxPro = max
    }

    fun setCanTouch(touch: Boolean) {
        isCanTouch = touch
    }

    interface OnRingViewListener {
        fun onProgressChange(progress: Int)
    }
}