package ocelot.desktop.ui.widget

import ocelot.desktop.ColorScheme
import ocelot.desktop.audio.SoundSource
import ocelot.desktop.color.Color
import ocelot.desktop.geometry.FloatUtils.ExtendedFloat
import ocelot.desktop.geometry.Size2D
import ocelot.desktop.graphics.Graphics
import ocelot.desktop.ui.event.handlers.{ClickHandler, DragHandler}
import ocelot.desktop.ui.event.{ClickEvent, DragEvent, MouseEvent}
import ocelot.desktop.util.DrawUtils

class Slider(var value: Float, val text: String, val snapPoints: Int = 0) extends Widget with ClickHandler with DragHandler with ClickSoundSource {
  def onValueChanged(value: Float): Unit = {}
  def onValueFinal(value: Float): Unit = {}

  override def receiveMouseEvents: Boolean = true

  private val handleWidth = 8.0f
  private var lastSoundX = 0.0f
  private val soundInterval = 3.0f

  private def calculateValue(x: Float): Unit = {
    value = ((x - bounds.x - handleWidth / 2f) / (bounds.w - handleWidth)).clamp(0f, 1f)
    onValueChanged(value)
  }


  eventHandlers += {
    case ClickEvent(MouseEvent.Button.Left, pos) =>
      calculateValue(pos.x)
      clickSoundSource.play()
      if (snapPoints > 1) {
        value = (value * (snapPoints - 1)).round / (snapPoints - 1).toFloat
      }
      onValueFinal(value)

    case DragEvent(DragEvent.State.Stop, MouseEvent.Button.Left, pos) =>
      calculateValue(pos.x)
      if (lastSoundX == 0 || (pos.x - lastSoundX).abs > soundInterval) {
        lastSoundX = pos.x
        clickSoundSource.play()
      }
      if (snapPoints > 1) {
        value = (value * (snapPoints - 1)).round / (snapPoints - 1).toFloat
      }
      onValueFinal(value)

    case DragEvent(_, MouseEvent.Button.Left, pos) =>
      calculateValue(pos.x)
      if (lastSoundX == 0 || (pos.x - lastSoundX).abs > soundInterval) {
        lastSoundX = pos.x
        clickSoundSource.play()
      }
  }

  override def minimumSize: Size2D = Size2D(24 + text.length * 8, 24)
  override def maximumSize: Size2D = minimumSize.copy(width = Float.PositiveInfinity)

  def formatText: String = f"$text: ${value * 100}%.0f%%"

  override def draw(g: Graphics): Unit = {
    g.rect(bounds, ColorScheme("SliderBackground"))
    DrawUtils.ring(g, position.x, position.y, width, height, 2, ColorScheme("SliderBorder"))

    for (i <- 1 until snapPoints - 1) {
      g.rect(position.x + (i / (snapPoints.toFloat - 1)) * (bounds.w - handleWidth / 2), position.y + 6, handleWidth / 2, height - 12, ColorScheme("SliderTick"))
    }

    g.rect(position.x + value * (bounds.w - handleWidth), position.y, handleWidth, height, ColorScheme("SliderHandler"))
    DrawUtils.ring(g, position.x + value * (bounds.w - handleWidth), position.y, handleWidth, height, 2, ColorScheme("SliderBorder"))

    g.background = Color.Transparent
    g.foreground = ColorScheme("SliderForeground")
    val textWidth = formatText.iterator.map(g.font.charWidth(_)).sum
    g.text(position.x + ((width - textWidth) / 2).round, position.y + 4, formatText)
  }

  override protected def clickSoundSource: SoundSource = SoundSource.InterfaceTick
}
