package com.gh.gamecenter.common.view

import android.animation.ArgbEvaluator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import androidx.annotation.ColorInt
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.utils.dip2px

class ScaleIndicatorView : View {

    private var argbEvaluator: ArgbEvaluator? = null

    private var mCurrentPosition = 0
    private var mSlideProgress = 0F
    var mPageSize = 0
    var mNormalSliderWidth = 0F
    var mCheckedSliderWidth = 0F
    var mSliderHeight = 0F
    var mSliderGap = 0F

    @ColorInt
    var mNormalColor = 0

    @ColorInt
    var mCheckedColor = 0

    private var mRectF = RectF()
    private var mPaint = Paint()

    private var maxWidth = 0F
    private var minWidth = 0F

    private val isWidthEquals
        get() = mNormalSliderWidth == mCheckedSliderWidth

    constructor(context: Context) : super(context, null) {
        initView(null)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs, 0) {
        initView(attrs)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        initView(attrs)
    }

    private fun initView(attrs: AttributeSet?) {
        if (attrs != null) {
            val ta = context.obtainStyledAttributes(attrs, R.styleable.ScaleIndicatorView)
            mNormalSliderWidth =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_normalSliderWidth, 10F.dip2px()).toFloat()
            mCheckedSliderWidth =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_checkedSliderWidth, 10F.dip2px()).toFloat()
            mSliderHeight =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_normalSliderWidth, 10F.dip2px()).toFloat()
            mSliderGap =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_normalSliderWidth, 10F.dip2px()).toFloat()
            mNormalColor = ta.getColor(R.styleable.ScaleIndicatorView_normalColor, Color.WHITE)
            mCheckedColor = ta.getColor(R.styleable.ScaleIndicatorView_checkedColor, Color.WHITE)
            ta.recycle()
        }
        mPaint.isAntiAlias = true
        argbEvaluator = ArgbEvaluator()
    }

    fun onPageScrolled(position: Int, positionOffset: Float) {
        if (mPageSize > 1) {
            scrollSlider(position, positionOffset)
            invalidate()
        }
    }

    fun notifyDataChanged() {
        requestLayout()
        invalidate()
    }

    private fun scrollSlider(
        position: Int,
        positionOffset: Float
    ) {
        mCurrentPosition = position
        mSlideProgress = positionOffset
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        maxWidth = mNormalSliderWidth.coerceAtLeast(mCheckedSliderWidth)
        minWidth = mNormalSliderWidth.coerceAtMost(mCheckedSliderWidth)
        setMeasuredDimension(measureWidth(), measureHeight())
    }

    private fun measureHeight() = mSliderHeight.toInt() + INDICATOR_PADDING

    private fun measureWidth() =
        ((mPageSize - 1) * mSliderGap + maxWidth + (mPageSize - 1) * minWidth).toInt() + INDICATOR_PADDING_ADDITION

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (mPageSize > 1) {
            if (isWidthEquals) {
                drawUncheckedSlider(canvas, mPageSize)
            } else {
                for (i in 0 until mPageSize) {
                    drawScaleSlider(canvas, i)
                }
            }
        }
    }

    private fun drawScaleSlider(
        canvas: Canvas?,
        i: Int
    ) {
        when {
            i < mCurrentPosition -> {
                mPaint.color = mNormalColor
                val left: Float = if (mCurrentPosition == mPageSize - 1) {
                    (i * mNormalSliderWidth + i * mSliderGap) + (mCheckedSliderWidth - mNormalSliderWidth) * mSlideProgress
                } else {
                    (i * mNormalSliderWidth + i * mSliderGap)
                }
                mRectF.set(left, 0f, left + mNormalSliderWidth, mSliderHeight)
                canvas?.drawRoundRect(mRectF, mSliderHeight, mSliderHeight, mPaint)
            }
            i == mCurrentPosition -> {
                mPaint.color = mCheckedColor
                val slideProgress = mSlideProgress
                if (mCurrentPosition == mPageSize - 1) {
                    val evaluate = argbEvaluator?.evaluate(
                        slideProgress, mCheckedColor, mNormalColor
                    )
                    mPaint.color = (evaluate as Int)
                    val right =
                        (mPageSize - 1) * (mNormalSliderWidth + mSliderGap) + mCheckedSliderWidth
                    val left =
                        right - mCheckedSliderWidth + (mCheckedSliderWidth - mNormalSliderWidth) * (slideProgress)
                    mRectF.set(left, 0f, right, mSliderHeight)
                    canvas?.drawRoundRect(mRectF, mSliderHeight, mSliderHeight, mPaint)
                } else {
                    if (slideProgress < 1) {
                        val evaluate = argbEvaluator?.evaluate(
                            slideProgress, mCheckedColor, mNormalColor
                        )
                        mPaint.color = (evaluate as Int)
                        val left = i * mNormalSliderWidth + i * mSliderGap
                        val right =
                            left + mNormalSliderWidth + (mCheckedSliderWidth - mNormalSliderWidth) * (1 - slideProgress)
                        mRectF.set(left, 0f, right, mSliderHeight)
                        canvas?.drawRoundRect(mRectF, mSliderHeight, mSliderHeight, mPaint)
                    }
                }

                if (mCurrentPosition == mPageSize - 1) {
                    if (slideProgress > 0) {
                        val evaluate = argbEvaluator?.evaluate(
                            1 - slideProgress, mCheckedColor, mNormalColor
                        )
                        mPaint.color = evaluate as Int
                        val left = 0f
                        val right =
                            left + mNormalSliderWidth + (mCheckedSliderWidth - mNormalSliderWidth) * slideProgress

                        mRectF.set(left, 0f, right, mSliderHeight)
                        canvas?.drawRoundRect(mRectF, mSliderHeight, mSliderHeight, mPaint)
                    }
                } else {
                    if (slideProgress > 0) {
                        val evaluate = argbEvaluator?.evaluate(
                            1 - slideProgress, mCheckedColor, mNormalColor
                        )
                        mPaint.color = evaluate as Int
                        val right =
                            i * mNormalSliderWidth + i * mSliderGap + mNormalSliderWidth + (mSliderGap + mCheckedSliderWidth)
                        val left =
                            right - (mNormalSliderWidth) - (mCheckedSliderWidth - mNormalSliderWidth) * (slideProgress)
                        mRectF.set(left, 0f, right, mSliderHeight)
                        canvas?.drawRoundRect(mRectF, mSliderHeight, mSliderHeight, mPaint)
                    }
                }
            }
            else -> {
                if ((mCurrentPosition + 1 != i || mSlideProgress == 0f)) { // 避免多余绘制
                    mPaint.color = mNormalColor
                    val left = i * minWidth + i * mSliderGap + (mCheckedSliderWidth - minWidth)
                    mRectF.set(left, 0f, left + minWidth, mSliderHeight)
                    canvas?.drawRoundRect(mRectF, mSliderHeight, mSliderHeight, mPaint)
                }
            }
        }
    }

    private fun drawUncheckedSlider(
        canvas: Canvas?,
        pageSize: Int
    ) {
        for (i in 0 until pageSize) {
            mPaint.color = mNormalColor
            val left = i * maxWidth + i * +mSliderGap + (maxWidth - minWidth)
            mRectF.set(left, 0f, left + minWidth, mSliderHeight)
            canvas?.drawRoundRect(mRectF, mSliderHeight, mSliderHeight, mPaint)
        }
    }

    companion object {
        const val INDICATOR_PADDING_ADDITION = 6
        const val INDICATOR_PADDING = 3
    }
}