package ocelot.desktop.inventory.traits

import ocelot.desktop.OcelotDesktop
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.node.nodes.RaidNode
import ocelot.desktop.ui.widget.DiskEditWindow
import ocelot.desktop.ui.widget.DiskEditWindow.{CanChangeManaged, EditableDisk, Lockable}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import ocelot.desktop.ui.widget.tooltip.ItemTooltip
import ocelot.desktop.ui.widget.window.{Window, Windowed}
import totoro.ocelot.brain.entity.traits.{Disk, DiskManaged, DiskRealPathAware, DiskUnmanaged, Entity}

import javax.swing.JFileChooser
import scala.util.Try

/**
  * A utility mixin for HDDs and floppies.
  */
trait DiskItem
  extends ComponentItem
    with EditableDisk
    with Lockable
    with CanChangeManaged
    with Windowed[DiskEditWindow] {

  override def entity: Entity with Disk

  override def disk: Option[Entity with Disk] = Option(entity)

  override def capacity: Long = disk.fold(0L)(_.capacity)

  override def lock(): Unit = reinserting {
    entity.setLocked(OcelotDesktop.player.nickname)
  }

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

  def editingAllowed: Boolean = {
    slot.fold(false)(_.inventory match {
      case _: RaidNode => false
      case _ => true
    })
  }

  override def fillRmbMenu(menu: ContextMenu): Unit = {
    if (editingAllowed) {
      // Real path
      entity match {
        case diskManaged: DiskManaged =>
          DiskItem.addRealPathContextMenuEntries(
            menu,
            diskManaged,
            realPathSetter => {
              reinserting {
                realPathSetter()
              }
            },
          )
        case _ =>
      }

      // Edit disk
      DiskItem.addEditDiskContextMenuEntries(menu, this)

      menu.addSeparator()
    }

    super.fillRmbMenu(menu)
  }

  protected def addDiskLabelTooltip(tooltip: ItemTooltip, label: String): Unit = {
    tooltip.addLine(s"Label: $label")
  }

  protected def addSourcePathTooltip(tooltip: ItemTooltip, disk: DiskManaged): Unit = {
    for (customRealPath <- disk.customRealPath) {
      tooltip.addLine(s"Source path: $customRealPath")
    }
  }

  protected def addManagedTooltip(tooltip: ItemTooltip, disk: Disk): Unit = {
    tooltip.addLine(disk match {
      case _: DiskManaged => "Mode: managed"
      case _: DiskUnmanaged => "Mode: unmanaged"
    })
  }

  override def fillTooltip(tooltip: ItemTooltip): Unit = {
    super.fillTooltip(tooltip)

    if (entity != null) {
      tooltip.addLine(s"Capacity: ${capacity / 1024} kB")
    }
  }
}

object DiskItem {
  def addRealPathContextMenuEntries(
    menu: ContextMenu,
    diskRealPathAware: DiskRealPathAware,
    realPathSetter: (() => Unit) => Unit,
  ): Unit = {
    menu.addEntry(ContextMenuEntry(
      if (diskRealPathAware.customRealPath.isDefined) "Change directory" else "Set directory",
      IconSource.Icons.Folder,
    ) {
      OcelotDesktop.showFileChooserDialog(JFileChooser.OPEN_DIALOG, JFileChooser.DIRECTORIES_ONLY) { dir =>
        Try {
          for (dir <- dir) {
            realPathSetter(() => {
              // trigger component_removed / component_added signals
              diskRealPathAware.customRealPath = Some(dir.toPath.toAbsolutePath)
            })
          }
        }
      }
    })

    if (diskRealPathAware.customRealPath.isDefined) {
      menu.addEntry(ContextMenuEntry("Reset directory", IconSource.Icons.FolderSlash) {
        realPathSetter(() => {
          // trigger component_removed / component_added signals
          diskRealPathAware.customRealPath = None
        })
      })
    }
  }

  def addEditDiskContextMenuEntries[T <: Window](menu: ContextMenu, windowed: Windowed[T]): Unit = {
    menu.addEntry(ContextMenuEntry("Edit disk", IconSource.Icons.Edit) {
      windowed.window.open()
    })
  }
}
