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


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

    private var totalLevels = 5
    private var currentLevel = 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 thumbBorderPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val nodePaint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 监听器
    private var onLevelChangeListener: OnLevelChangeListener? = null
    private var isDragging = false


    // 触摸相关
    private var lastTouchX = 0f



    interface OnLevelChangeListener {
        fun onLevelChanged(seekBar: LevelSeekBar, level: Int, fromUser: Boolean)
        fun onStartTrackingTouch(seekBar: LevelSeekBar)
        fun onStopTrackingTouch(seekBar: LevelSeekBar)
    }

    init {
        setupAttributes(attrs)
        setupPaints()
    }

    private fun setupAttributes(attrs: AttributeSet?) {
        attrs?.let {
            val typedArray = context.obtainStyledAttributes(it, R.styleable.CustomLevelSeekBar)

            totalLevels = typedArray.getInt(R.styleable.CustomLevelSeekBar_totalLevels, totalLevels)
            currentLevel = typedArray.getInt(R.styleable.CustomLevelSeekBar_currentLevel, currentLevel)
                .coerceIn(0, totalLevels - 1)

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

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

            typedArray.recycle()
        }
    }

    private fun setupPaints() {
        trackPaint.style = Paint.Style.FILL

        thumbBorderPaint.style = Paint.Style.STROKE
        //thumbBorderPaint.strokeWidth = 1F.dp.toFloat()
        thumbBorderPaint.color = thumbBorderColor

        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 + nodeWidth/2, trackTop, width.toFloat(), trackBottom - nodeWidth/2)
        canvas.drawRoundRect(trackRect, trackEndRadius, trackEndRadius, trackPaint)
    }

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

        val centerY = height / 2f

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

            nodePaint.color = if (i <= currentLevel) activeNodeColor else nodeColor
            //canvas.drawCircle(x, centerY, nodeRadius, nodePaint)
            val trackRect = RectF(x - thumbRadius/2, centerY - nodeHeight/2 + 6, x + thumbRadius/2, centerY + nodeHeight/2)
            canvas.drawRoundRect(trackRect, trackEndRadius, trackEndRadius, nodePaint)
        }
    }

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

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

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

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

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

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (isPointInThumb(event.x, event.y) || isPointInTrack(event.x, event.y)) {
                    isDragging = true
                    lastTouchX = event.x
                    onLevelChangeListener?.onStartTrackingTouch(this)
                    handleTouch(event.x)
                    parent?.requestDisallowInterceptTouchEvent(true)
                    return true
                }
            }

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

            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                if (isDragging) {
                    isDragging = false
                    snapToNearestLevel(lastTouchX)
                    onLevelChangeListener?.onStopTrackingTouch(this)
                    parent?.requestDisallowInterceptTouchEvent(false)
                    return true
                }
            }
        }
        return super.onTouchEvent(event)
    }

    private fun isPointInThumb(x: Float, y: Float): Boolean {
        val thumbX = calculatePositionForLevel(currentLevel)
        val centerY = height / 2f
        val distance = Math.sqrt(
            (x - thumbX) * (x - thumbX) + (y - centerY) * (y - centerY).toDouble()
        )
        return distance <= thumbRadius
    }

    private fun isPointInTrack(x: Float, y: Float): Boolean {
        val centerY = height / 2f
        val trackTop = centerY - trackHeight / 2 - thumbRadius // 扩大触摸区域
        val trackBottom = centerY + trackHeight / 2 + thumbRadius
        return x in 0f..width.toFloat() && y in trackTop..trackBottom
    }

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

        val newLevel = calculateLevelForPosition(x)
        if (newLevel != currentLevel) {
            currentLevel = newLevel
            invalidate()
            onLevelChangeListener?.onLevelChanged(this, currentLevel, true)
        }
    }

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

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

        if (newLevel != currentLevel) {
            currentLevel = newLevel
            invalidate()
            onLevelChangeListener?.onLevelChanged(this, currentLevel, true)
        }
    }

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

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

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

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




    //---------------------------- public 设置方法 ---------------------------------//
    fun setLevel(level: Int, fromUser: Boolean = false) {
        val newLevel = level.coerceIn(0, totalLevels - 1)
        if (newLevel != currentLevel) {
            currentLevel = newLevel
            invalidate()
            onLevelChangeListener?.onLevelChanged(this, currentLevel, fromUser)
        }
    }

    fun getLevel(): Int = currentLevel

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

    fun getTotalLevels(): Int = totalLevels

    fun setOnLevelChangeListener(listener: OnLevelChangeListener) {
        this.onLevelChangeListener = listener
    }


    fun setOnLevelChangeListener(
        onLevelChanged: (LevelSeekBar, Int, Boolean) -> Unit = { _, _, _ -> },
        onStartTrackingTouch: (LevelSeekBar) -> Unit = {},
        onStopTrackingTouch: (LevelSeekBar) -> Unit = {}
    ) {
        this.onLevelChangeListener = object : OnLevelChangeListener {
            override fun onLevelChanged(seekBar: LevelSeekBar, level: Int, fromUser: Boolean) {
                onLevelChanged(seekBar, level, fromUser)
            }
            override fun onStartTrackingTouch(seekBar: LevelSeekBar) {
                onStartTrackingTouch(seekBar)
            }
            override fun onStopTrackingTouch(seekBar: LevelSeekBar) {
                onStopTrackingTouch(seekBar)
            }
        }
    }

    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)
    }

}