package ocelot.desktop.inventory.item

import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color
import ocelot.desktop.entity.OcelotCard
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.inventory.item.OcelotCardItem.MessagesTag
import ocelot.desktop.inventory.traits.{CardItem, ComponentItem, PersistableItem}
import ocelot.desktop.inventory.{Item, ItemFactory, ItemRecoverer}
import ocelot.desktop.ui.event.BrainEvent
import ocelot.desktop.ui.widget.card.OcelotCardWindow
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import ocelot.desktop.ui.widget.window.Windowed
import totoro.ocelot.brain.nbt.ExtendedNBT.extendNBTTagList
import totoro.ocelot.brain.nbt.{NBT, NBTBase, NBTTagCompound, NBTTagString}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier

import scala.collection.{IndexedSeqView, mutable}
import scala.jdk.CollectionConverters.BufferHasAsJava

class OcelotCardItem(val ocelotCard: OcelotCard)
  extends Item
    with ComponentItem
    with PersistableItem
    with CardItem
    with Windowed[OcelotCardWindow] {

  private var _messageLimit: Int = 1000

  private val _messages = mutable.ArrayDeque.empty[String]

  def messages: IndexedSeqView[String] = _messages.view

  eventHandlers += {
    case BrainEvent(OcelotCard.LogEvent(_, message)) =>
      addMessage(message)
  }

  override def createWindow(): OcelotCardWindow = new OcelotCardWindow(this)

  override def component: OcelotCard = ocelotCard

  override def tooltipNameColor: Color = ColorScheme("OcelotCardTooltip")

  override def fillRmbMenu(menu: ContextMenu): Unit = {
    menu.addEntry(ContextMenuEntry("Open console", IconSource.Window) {
      window.open()
    })

    menu.addSeparator()

    super.fillRmbMenu(menu)
  }

  override def load(nbt: NBTTagCompound): Unit = {
    super.load(nbt)

    clear()
    addMessages(nbt.getTagList(MessagesTag, NBT.TAG_STRING).iterator[NBTTagString].map(_.getString).toSeq)
  }

  override def save(nbt: NBTTagCompound): Unit = {
    super.save(nbt)
    nbt.setTagList(MessagesTag, _messages.map(new NBTTagString(_).asInstanceOf[NBTBase]).asJava)
  }

  override def factory: ItemFactory = OcelotCardItem.Factory

  def messageLimit: Int = _messageLimit

  def messageLimit_=(limit: Int): Unit = {
    require(limit > 0)
    ensureFreeSpace(_messages.length - limit)
    _messageLimit = limit
  }

  def clear(): Unit = {
    val count = _messages.length
    _messages.clear()
    window.onMessagesRemoved(count)
  }

  private def addMessage(message: String): Unit = {
    ensureFreeSpace(1)
    _messages += message
    window.onMessagesAdded(1)
  }

  private def addMessages(messages: Seq[String]): Unit = {
    ensureFreeSpace(messages.length)
    val prevCount = _messages.length
    _messages ++= messages.view.takeRight(messageLimit)
    window.onMessagesAdded(_messages.length - prevCount)
  }

  private def ensureFreeSpace(n: Int): Unit = {
    val prevCount = _messages.length
    _messages.takeRightInPlace(messageLimit - n)
    val removedCount = prevCount - _messages.length

    if (removedCount > 0) {
      window.onMessagesRemoved(removedCount)
    }
  }
}

object OcelotCardItem {
  val MessagesTag = "messages"

  object Factory extends ItemFactory {
    override type I = OcelotCardItem

    override def itemClass: Class[I] = classOf

    override def name: String = "Ocelot Card"

    override def tier: Option[Tier] = Some(Tier.One)

    override def icon: IconSource = IconSource.OcelotCard

    override def build(): OcelotCardItem = new OcelotCardItem(new OcelotCard)

    override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new OcelotCardItem(_)))
  }
}
