package net.torvald.terrarum.ui

import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion
import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import kotlin.math.roundToInt

/**
 * Created by minjaesong on 2023-09-17.
 */
class UIItemVertSlider(
    parentUI: UICanvas,
    initialX: Int, initialY: Int,
    private var initialValue: Double,
    val min: Double,
    val max: Double,
    override val height: Int,
    val handleHeight: Int = 12,
    private val backgroundTexture: TextureRegion? = null,
    private val disposeTexture: Boolean = false
) : UIItem(parentUI, initialX, initialY) {

    companion object {
        const val WIDTH = 16
    }

    override val width = WIDTH
    private var mouseOnHandle = false

    private val handleTravelDist = height - handleHeight
    private var handlePos = if (max == 0.0) 0.0 else (initialValue / max).times(handleTravelDist).coerceIn(0.0, handleTravelDist.toDouble())

    var value: Double = initialValue; private set
    var selectionChangeListener: (Double) -> Unit = {}

    private var mouseLatched = false // trust me this one needs its own binary latch

    init {
        printdbg(this, "slider max=$max")
    }

    override fun update(delta: Float) {
        super.update(delta)

        mouseOnHandle = itemRelativeMouseY in handlePos.roundToInt() until handlePos.roundToInt() + handleHeight && itemRelativeMouseX in 0 until width

        // update handle position and value
        if (mouseUp && Terrarum.mouseDown || mouseLatched) {
            mouseLatched = true
            handlePos = (itemRelativeMouseY - handleHeight/2.0).coerceIn(0.0, handleTravelDist.toDouble())
            value = interpolateLinear(handlePos / handleTravelDist, min, max)
            selectionChangeListener(value)
        }

        if (!Terrarum.mouseDown) {
            mouseLatched = false
        }
    }

    val troughBorderCol: Color; get() = if (mouseUp || mouseLatched) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_INACTIVE
    val handleCol: Color; get() = if (mouseOnHandle && mousePushed || mouseLatched) Toolkit.Theme.COL_SELECTED
    else if (mouseOnHandle) Toolkit.Theme.COL_MOUSE_UP else Color.WHITE

    private val renderJobs = arrayOf(
        // trough fill
        { batch: SpriteBatch ->
            if (backgroundTexture != null) {
                batch.color = Color.WHITE
                batch.draw(backgroundTexture, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
            }
            else {
                batch.color = UIItemTextLineInput.TEXTINPUT_COL_BACKGROUND
                Toolkit.fillArea(batch, posX, posY, width, height)
            }
        },
        // trough border
        { batch: SpriteBatch ->
            batch.color = troughBorderCol
            Toolkit.drawBoxBorder(batch, posX - 1, posY - 1, width + 2, height + 2)
        },
        // handle fill
        { batch: SpriteBatch ->
            batch.color = handleCol.cpy().mul(Color.LIGHT_GRAY)
            Toolkit.fillArea(batch, posX, posY + handlePos.roundToInt(), width, handleHeight)
        },
        // handle border
        { batch: SpriteBatch ->
            batch.color = handleCol
            Toolkit.drawBoxBorder(batch, posX - 1, posY + handlePos.roundToInt() - 1, width + 2, handleHeight + 2)
        },
    )

    private val renderOrderMouseUp = arrayOf(0,2,3,1).map { renderJobs[it] }

    override fun render(frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera) {
        blendNormalStraightAlpha(batch)
        renderOrderMouseUp.forEach { it(batch) }

        super.render(frameDelta, batch, camera)
    }

    override fun dispose() {
        if (disposeTexture) backgroundTexture?.texture?.tryDispose()
    }

    fun scrolledForce(amountX: Float, amountY: Float): Boolean {
        val move = Math.round(amountY)
        val newValue = (value + move).coerceIn(min, max)

        handlePos = interpolateLinear(newValue / max, 0.0, handleTravelDist.toDouble())
        value = newValue
        selectionChangeListener(value)

        return true
    }
}