package ocelot.desktop.windows

import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.ui.event.KeyEvent
import ocelot.desktop.ui.layout.{AlignItems, Layout, LinearLayout}
import ocelot.desktop.ui.widget.LogWidget.{LogEntry, TextLogEntry}
import ocelot.desktop.ui.widget.window.PanelWindow
import ocelot.desktop.ui.widget.{Button, Checkbox, Filler, Label, LogWidget, PaddingBox, TextInput, Widget}
import ocelot.desktop.util.{OcelotInterfaceLogStorage, Orientation}
import ocelot.desktop.windows.OcelotInterfaceWindow.ScrollToEndTag
import org.lwjgl.input.Keyboard
import totoro.ocelot.brain.nbt.NBTTagCompound

class OcelotInterfaceWindow(storage: OcelotInterfaceLogStorage) extends PanelWindow {
  override protected def title: String = s"${storage.name} ${storage.ocelotInterface.node.address}"

  private val logWidget: LogWidget = new LogWidget {
    override protected def textWidth: Int = 50
    override def minimumSize: Size2D = super.minimumSize.copy(height = 300)
    override def maximumSize: Size2D = minimumSize
  }

  setInner(new Widget {
    override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical, gap = 4f)

    children :+= logWidget

    var historyPosition = 0
    var unfinishedEntryBackup: Option[String] = None

    children :+= new TextInput() {
      eventHandlers += {
        case event @ KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, Keyboard.KEY_UP | Keyboard.KEY_DOWN, _) if isFocused =>
          val currentInput = text
          val index = if (event.code == Keyboard.KEY_UP) {
            storage.findLastTextEntry(currentInput, storage.entryCount - historyPosition)
          } else {
            storage.findFirstTextEntry(currentInput, storage.entryCount - historyPosition + 1)
          }
          if (index != -1) {
            if (unfinishedEntryBackup.isEmpty) {
              unfinishedEntryBackup = Some(currentInput)
            }
            historyPosition = storage.entryCount - index
            text = storage.getEntry(index).asInstanceOf[TextLogEntry].message
            event.consume()
          } else if (event.code == Keyboard.KEY_DOWN && unfinishedEntryBackup.nonEmpty) {
            text = unfinishedEntryBackup.get
            unfinishedEntryBackup = None
          }
      }

      override def onConfirm(): Unit = {
        pushLine(text)
        text = ""
        unfinishedEntryBackup = None
        historyPosition = 0
      }
    }

    children :+= new Label {
      override def text: String = s"Messages: ${storage.entryCount} / ${storage.messageLimit}"
    }

    children :+= new Widget {
      override protected val layout: Layout =
        new LinearLayout(this, orientation = Orientation.Horizontal, alignItems = AlignItems.Center)

      children :+= new PaddingBox(
        new Label {
          override def text: String = "Limit"

          override def maximumSize: Size2D = minimumSize
        },
        Padding2D(right = 12),
      )

      children :+= new TextInput(storage.messageLimit.toString) {
        private def parseInput(text: String): Option[Int] = text.toIntOption.filter(_ > 0)

        override def minimumSize: Size2D = super.minimumSize.copy(width = 60)

        override def maximumSize: Size2D = minimumSize

        override def validator(text: String): Boolean = parseInput(text).nonEmpty

        override def onConfirm(): Unit = {
          for (messageLimit <- parseInput(text)) {
            storage.messageLimit = messageLimit
          }

          super.onConfirm()
        }
      }

      children :+= new Filler

      children :+= new Checkbox("Scroll to end") {
        override def checked: Boolean = logWidget.scrollToEnd

        override def checked_=(value: Boolean): Unit = {
          logWidget.scrollToEnd = value
        }
      }

      children :+= new Button {
        override def text: String = "Clear"
        override def onClick(): Unit = {
          unfinishedEntryBackup = None
          historyPosition = 0
          clear()
        }
      }
    }
  })

  private def clear(): Unit = {
    storage.clear()
  }

  def onMessagesAdded(entries: Iterable[LogEntry]): Unit = {
    logWidget.addEntries(entries)
  }

  def onMessagesRemoved(count: Int): Unit = {
    logWidget.removeFirstEntries(count)
  }

  def pushLine(line: String): Unit = {
    storage.ocelotInterface.pushMessage(line)
  }

  override def save(nbt: NBTTagCompound): Unit = {
    super.save(nbt)
    nbt.setBoolean(ScrollToEndTag, logWidget.scrollToEnd)
  }

  override def load(nbt: NBTTagCompound): Unit = {
    super.load(nbt)
    if (nbt.hasKey(ScrollToEndTag)) {
      logWidget.scrollToEnd = nbt.getBoolean(ScrollToEndTag)
    }
  }
}

object OcelotInterfaceWindow {
  private val ScrollToEndTag = "scrollToEnd"
}
