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 mArgbEvaluator: ArgbEvaluator? = null

    private var mCurrentPosition = 0
    private var mSlideProgress = 0F
    var pageSize = 0
    var normalSliderWidth = 0F
    var checkedSliderWidth = 0F
    var sliderHeight = 0F
    var sliderGap = 0F

    @ColorInt
    var normalColor = 0

    @ColorInt
    var checkedColor = 0

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

    private var mMaxWidth = 0F
    private var mMinWidth = 0F

    private val mIsWidthEquals
        get() = normalSliderWidth == checkedSliderWidth

    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)
            normalSliderWidth =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_normalSliderWidth, 10F.dip2px()).toFloat()
            checkedSliderWidth =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_checkedSliderWidth, 10F.dip2px()).toFloat()
            sliderHeight =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_sliderHeight, 10F.dip2px()).toFloat()
            sliderGap =
                ta.getDimensionPixelSize(R.styleable.ScaleIndicatorView_sliderGap, 10F.dip2px()).toFloat()
            normalColor = ta.getColor(R.styleable.ScaleIndicatorView_normalColor, Color.WHITE)
            checkedColor = ta.getColor(R.styleable.ScaleIndicatorView_checkedColor, Color.WHITE)
            ta.recycle()
        }
        mPaint.isAntiAlias = true
        mArgbEvaluator = ArgbEvaluator()
    }

    fun onPageScrolled(position: Int, positionOffset: Float) {
        if (pageSize > 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)
        mMaxWidth = normalSliderWidth.coerceAtLeast(checkedSliderWidth)
        mMinWidth = normalSliderWidth.coerceAtMost(checkedSliderWidth)
        setMeasuredDimension(measureWidth(), measureHeight())
    }

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

    private fun measureWidth() =
        ((pageSize - 1) * sliderGap + mMaxWidth + (pageSize - 1) * mMinWidth).toInt() + INDICATOR_PADDING_ADDITION

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

    private fun drawScaleSlider(
        canvas: Canvas?,
        i: Int
    ) {
        when {
            i < mCurrentPosition -> {
                mPaint.color = normalColor
                val left: Float = if (mCurrentPosition == pageSize - 1) {
                    (i * normalSliderWidth + i * sliderGap) + (checkedSliderWidth - normalSliderWidth) * mSlideProgress
                } else {
                    (i * normalSliderWidth + i * sliderGap)
                }
                mRectF.set(left, 0f, left + normalSliderWidth, sliderHeight)
                canvas?.drawRoundRect(mRectF, sliderHeight, sliderHeight, mPaint)
            }
            i == mCurrentPosition -> {
                mPaint.color = checkedColor
                val slideProgress = mSlideProgress
                if (mCurrentPosition == pageSize - 1) {
                    val evaluate = mArgbEvaluator?.evaluate(
                        slideProgress, checkedColor, normalColor
                    )
                    mPaint.color = (evaluate as Int)
                    val right =
                        (pageSize - 1) * (normalSliderWidth + sliderGap) + checkedSliderWidth
                    val left =
                        right - checkedSliderWidth + (checkedSliderWidth - normalSliderWidth) * (slideProgress)
                    mRectF.set(left, 0f, right, sliderHeight)
                    canvas?.drawRoundRect(mRectF, sliderHeight, sliderHeight, mPaint)
                } else {
                    if (slideProgress < 1) {
                        val evaluate = mArgbEvaluator?.evaluate(
                            slideProgress, checkedColor, normalColor
                        )
                        mPaint.color = (evaluate as Int)
                        val left = i * normalSliderWidth + i * sliderGap
                        val right =
                            left + normalSliderWidth + (checkedSliderWidth - normalSliderWidth) * (1 - slideProgress)
                        mRectF.set(left, 0f, right, sliderHeight)
                        canvas?.drawRoundRect(mRectF, sliderHeight, sliderHeight, mPaint)
                    }
                }

                if (mCurrentPosition == pageSize - 1) {
                    if (slideProgress > 0) {
                        val evaluate = mArgbEvaluator?.evaluate(
                            1 - slideProgress, checkedColor, normalColor
                        )
                        mPaint.color = evaluate as Int
                        val left = 0f
                        val right =
                            left + normalSliderWidth + (checkedSliderWidth - normalSliderWidth) * slideProgress

                        mRectF.set(left, 0f, right, sliderHeight)
                        canvas?.drawRoundRect(mRectF, sliderHeight, sliderHeight, mPaint)
                    }
                } else {
                    if (slideProgress > 0) {
                        val evaluate = mArgbEvaluator?.evaluate(
                            1 - slideProgress, checkedColor, normalColor
                        )
                        mPaint.color = evaluate as Int
                        val right =
                            i * normalSliderWidth + i * sliderGap + normalSliderWidth + (sliderGap + checkedSliderWidth)
                        val left =
                            right - (normalSliderWidth) - (checkedSliderWidth - normalSliderWidth) * (slideProgress)
                        mRectF.set(left, 0f, right, sliderHeight)
                        canvas?.drawRoundRect(mRectF, sliderHeight, sliderHeight, mPaint)
                    }
                }
            }
            else -> {
                if ((mCurrentPosition + 1 != i || mSlideProgress == 0f)) { // 避免多余绘制
                    mPaint.color = normalColor
                    val left = i * mMinWidth + i * sliderGap + (checkedSliderWidth - mMinWidth)
                    mRectF.set(left, 0f, left + mMinWidth, sliderHeight)
                    canvas?.drawRoundRect(mRectF, sliderHeight, sliderHeight, mPaint)
                }
            }
        }
    }

    private fun drawUncheckedSlider(
        canvas: Canvas?,
        pageSize: Int
    ) {
        for (i in 0 until pageSize) {
            mPaint.color = normalColor
            val left = i * mMaxWidth + i * +sliderGap + (mMaxWidth - mMinWidth)
            mRectF.set(left, 0f, left + mMinWidth, sliderHeight)
            canvas?.drawRoundRect(mRectF, sliderHeight, sliderHeight, mPaint)
        }
    }

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