package com.remax.visualnovel.ui.chat.ui


import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.remax.visualnovel.R
import com.remax.visualnovel.utils.ResUtil
import com.remax.visualnovel.utils.spannablex.utils.dp
import androidx.core.content.withStyledAttributes



class LevelSeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private var mTotalLevel = 5
    private var mCurLevel = 2

    // 尺寸
    private var trackHeight = ResUtil.getPixelSize(R.dimen.dp_5).toFloat()
    private var trackEndRadius = ResUtil.getPixelSize(R.dimen.dp_8).toFloat()
    private var thumbRadius = ResUtil.getPixelSize(R.dimen.dp_9).toFloat()
    private var nodeRadius = ResUtil.getPixelSize(R.dimen.dp_3).toFloat()
    private val nodeWidth = ResUtil.getPixelSize(R.dimen.dp_5)
    private val nodeHeight= ResUtil.getPixelSize(R.dimen.dp_11)


    // 颜色
    private var trackColor = ResUtil.getColor(R.color.seekbar_color)
    private var thumbColor = ResUtil.getColor(R.color.white)
    private var activeTrackColor = trackColor
    private var thumbBorderColor = trackColor
    private var nodeColor = trackColor
    private var activeNodeColor = trackColor


    // 画笔
    private val trackPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val thumbPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val nodePaint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 监听器
    private var onLevelChangeListener: OnLevelChangeListener? = null
    private var lastTouchX = 0f



    interface OnLevelChangeListener {
        fun onLevelChanged(level: Int)
    }

    init {
        setupAttributes(attrs)
        setupPaints()
    }

    private fun setupAttributes(attrs: AttributeSet?) {
        attrs?.let {
            context.withStyledAttributes(it, R.styleable.CustomLevelSeekBar) {
                mTotalLevel = getInt(R.styleable.CustomLevelSeekBar_totalLevels, mTotalLevel)
                mCurLevel = getInt(R.styleable.CustomLevelSeekBar_currentLevel, mCurLevel)
                    .coerceIn(0, mTotalLevel - 1)

                trackColor = getColor(R.styleable.CustomLevelSeekBar_trackColor, trackColor)
                activeTrackColor =
                    getColor(R.styleable.CustomLevelSeekBar_activeTrackColor, activeTrackColor)
                thumbColor = getColor(R.styleable.CustomLevelSeekBar_thumbColor, thumbColor)
                thumbBorderColor =
                    getColor(R.styleable.CustomLevelSeekBar_thumbBorderColor, thumbBorderColor)
                nodeColor = getColor(R.styleable.CustomLevelSeekBar_nodeColor, nodeColor)
                activeNodeColor =
                    getColor(R.styleable.CustomLevelSeekBar_activeNodeColor, activeNodeColor)

                trackHeight = getDimension(R.styleable.CustomLevelSeekBar_trackHeight, trackHeight)
                trackEndRadius =
                    getDimension(R.styleable.CustomLevelSeekBar_trackEndRadius, trackEndRadius)
                thumbRadius = getDimension(R.styleable.CustomLevelSeekBar_thumbRadius, thumbRadius)
                nodeRadius = getDimension(R.styleable.CustomLevelSeekBar_nodeRadius, nodeRadius)

            }
        }
    }

    private fun setupPaints() {
        trackPaint.style = Paint.Style.FILL
        thumbPaint.style = Paint.Style.FILL
        thumbPaint.color = thumbColor
        nodePaint.style = Paint.Style.FILL
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawTrack(canvas)
        drawNodes(canvas)
        drawThumb(canvas)
    }

    private fun drawTrack(canvas: Canvas) {
        val centerY = height / 2f
        val trackTop = centerY - trackHeight / 2
        val trackBottom = centerY + trackHeight / 2

        trackPaint.color = trackColor
        val trackRect = RectF(0f + thumbRadius, trackTop, width.toFloat() - thumbRadius, trackBottom)
        canvas.drawRoundRect(trackRect, trackEndRadius, trackEndRadius, trackPaint)
    }

    private fun drawNodes(canvas: Canvas) {
        if (mTotalLevel <= 1) return

        val centerY = height / 2f

        for (i in 0 until mTotalLevel) {
            val x = calculatePositionForLevel(i)

            nodePaint.color = if (i <= mCurLevel) activeNodeColor else nodeColor
            val trackRect = RectF(x - nodeWidth/2, centerY - nodeHeight/2, x + nodeWidth/2, centerY + nodeHeight/2)
            canvas.drawRoundRect(trackRect, trackEndRadius, trackEndRadius, nodePaint)
        }
    }

    private fun drawThumb(canvas: Canvas) {
        if (mTotalLevel <= 1) return

        val centerY = height / 2f
        val thumbX = calculatePositionForLevel(mCurLevel)

        canvas.drawCircle(thumbX, centerY, thumbRadius - 1F.dp.toFloat(), thumbPaint)
    }

    private fun calculatePositionForLevel(level: Int): Float {
        if (mTotalLevel <= 1) return width / 2f

        val availableWidth = width - 2 * thumbRadius
        return thumbRadius + (availableWidth * level.toFloat() / (mTotalLevel - 1))
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                lastTouchX = event.x
                handleTouch(event.x)
                parent?.requestDisallowInterceptTouchEvent(true)
                return true
            }

            MotionEvent.ACTION_MOVE -> {
                lastTouchX = event.x
                handleTouch(event.x)
                return true
            }

            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                snapToNearestLevel(lastTouchX)
                parent?.requestDisallowInterceptTouchEvent(false)
                return true
            }
        }
        return super.onTouchEvent(event)
    }

    private fun handleTouch(x: Float) {
        if (mTotalLevel <= 1) return

        val newLevel = calculateLevelForPosition(x)
        if (newLevel != mCurLevel) {
            mCurLevel = newLevel
            invalidate()
        }
    }

    private fun snapToNearestLevel(x: Float) {
        if (mTotalLevel <= 1) return

        val exactLevel = calculateExactLevelForPosition(x)
        val newLevel = (exactLevel + 0.5f).toInt().coerceIn(0, mTotalLevel - 1)

        mCurLevel = newLevel
        invalidate()
        onLevelChangeListener?.onLevelChanged(mCurLevel)
    }

    private fun calculateLevelForPosition(x: Float): Int {
        if (mTotalLevel <= 1) return 0

        val availableWidth = width - 2 * thumbRadius
        val progress = ((x - thumbRadius) / availableWidth).coerceIn(0f, 1f)
        return (progress * (mTotalLevel - 1)).toInt().coerceIn(0, mTotalLevel - 1)
    }

    private fun calculateExactLevelForPosition(x: Float): Float {
        if (mTotalLevel <= 1) return 0f

        val availableWidth = width - 2 * thumbRadius
        val progress = ((x - thumbRadius) / availableWidth).coerceIn(0f, 1f)
        return progress * (mTotalLevel - 1)
    }




    //---------------------------- public 设置方法 ---------------------------------//
    fun setLevel(level: Int, fromUser: Boolean = false) {
        val newLevel = level.coerceIn(0, mTotalLevel - 1)
        if (newLevel != mCurLevel) {
            mCurLevel = newLevel
            invalidate()
        }
    }

    fun getLevel(): Int = mCurLevel

    fun setTotalLevels(levels: Int) {
        if (levels > 0 && levels != mTotalLevel) {
            mTotalLevel = levels
            mCurLevel = mCurLevel.coerceIn(0, mTotalLevel - 1)
            invalidate()
        }
    }

    fun getTotalLevels(): Int = mTotalLevel


    fun setOnLevelChangeListener(
        onLevelChanged: (Int) -> Unit
    ) {
        this.onLevelChangeListener = object : OnLevelChangeListener {
            override fun onLevelChanged(level: Int) {
                onLevelChanged(level)
            }
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val minWidth = suggestedMinimumWidth + paddingLeft + paddingRight
        val minHeight = (thumbRadius * 2 + paddingTop + paddingBottom).toInt()

        val width = resolveSizeAndState(minWidth, widthMeasureSpec, 1)
        val height = resolveSizeAndState(minHeight, heightMeasureSpec, 1)

        setMeasuredDimension(width, height)
    }

}