package ocelot.desktop.ui.widget

import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color
import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.ui.layout.{AlignItems, LinearLayout}
import ocelot.desktop.ui.widget.DiskEditWindow.{CanChangeManaged, EditableDisk, HasColor, Lockable}
import ocelot.desktop.ui.widget.window.PanelWindow
import ocelot.desktop.util.SizeFormatting.formatSize
import ocelot.desktop.util.animation.ColorAnimation
import ocelot.desktop.util.{DiskDriveAware, Orientation}
import totoro.ocelot.brain.entity.traits.{DiskManaged, DiskUnmanaged, Environment}
import totoro.ocelot.brain.util.DyeColor

class DiskEditWindow(disk: EditableDisk) extends PanelWindow {
  private def diskSize: Option[Long] = disk.disk.collect { case disk: DiskManaged =>
    disk.fileSystem.fileSystem.spaceUsed
  }

  private def isWriteable: Boolean = disk.disk match {
    case Some(disk: DiskManaged) => !disk.fileSystem.fileSystem.isReadOnly
    case Some(disk: DiskUnmanaged) => !disk.isLocked
    case None => false
  }

  private def isManaged: Boolean = disk.disk match {
    case Some(_: DiskManaged) => true
    case Some(_: DiskUnmanaged) => false
    case None => false
  }

  override protected def title: String = s"${disk.diskKind} " + disk.diskAddress.getOrElse("")

  override protected def titleMaxLength: Int = 32

  setInner(new Widget {
    override val layout = new LinearLayout(this, orientation = Orientation.Vertical)

    children :+= new PaddingBox(
      new Label {
        override def text: String = diskSize match {
          case Some(used) => s"Used: ${formatSize(used)} / ${formatSize(disk.capacity)}"
          case None => s"Capacity: ${formatSize(disk.capacity)}"
        }
      },
      Padding2D(bottom = 12),
    )

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

        children :+= new Label("Label")

        children :+= new TextInput(disk.diskLabel.getOrElse("")) {
          override def onConfirm(): Unit = {
            super.onConfirm()
            disk.diskLabel = Some(text).filter(_.nonEmpty)
          }

          override def enabled: Boolean = disk.editingAllowed && disk.isLabelWriteable
        }
      },
      Padding2D(bottom = 12),
    )

    disk match {
      case disk: EditableDisk with HasColor =>
        val colorSelector: Widget = new Widget {
          override val layout = new LinearLayout(this, orientation = Orientation.Vertical, gap = 2)

          for (row <- DyeColor.All.iterator.grouped(8)) {
            children :+= new Widget {
              override val layout = new LinearLayout(this, orientation = Orientation.Horizontal, gap = 2)

              for (dyeColor <- row) {
                def isColorSelected: Boolean = dyeColor == disk.color

                val floppyIcon = IconSource.Items.FloppyDisk(dyeColor)
                children :+= new IconButton(
                  floppyIcon,
                  floppyIcon,
                  mode = IconButton.Mode.Radio,
                  drawBackground = true,
                  tooltip = Some(DiskDriveAware.ColorNames(dyeColor)),
                  padding = 2,
                  sizeMultiplier = 2f,
                  model = IconButton.ReadOnlyModel(isColorSelected),
                ) {
                  private val borderAnimation = new ColorAnimation(targetBorderColor, IconButton.AnimationSpeed)

                  private def targetBorderColor: Color =
                    if (isColorSelected) ColorScheme("FloppyIconButtonBorderSelected")
                    else ColorScheme("ButtonBorder")

                  override protected def updateAnimationTargets(): Unit = {
                    super.updateAnimationTargets()
                    borderAnimation.goto(targetBorderColor)
                  }

                  override def borderColor: Color = borderAnimation.color

                  override def onPressed(): Unit = {
                    if (disk.editingAllowed && !isColorSelected) {
                      disk.color = dyeColor
                    }
                  }

                  override def update(): Unit = {
                    super.update()
                    borderAnimation.update()
                  }
                }
              }

            }
          }
        }

        children :+= new PaddingBox(colorSelector, Padding2D(bottom = 12))

      case _ =>
    }

    private object BottomRow extends Widget {
      override val layout = new LinearLayout(this, orientation = Orientation.Horizontal, gap = 8)

      disk match {
        case disk: EditableDisk with Lockable =>
          children :+= new Button {
            override def text: String = "Make read-only"

            override def onClick(): Unit = {
              if (disk.editingAllowed) {
                disk.lock()
              }
            }

            override def enabled: Boolean = isWriteable
          }

        case _ =>
      }

      disk match {
        case disk: EditableDisk with CanChangeManaged =>
          children :+= new Button {
            override def text: String = s"Make ${if (isManaged) "unmanaged" else "managed"}"

            override def onClick(): Unit = {
              if (disk.editingAllowed) {
                disk.setManaged(!isManaged)
              }
            }

            override def maximumSize: Size2D = super.maximumSize.copy(width = Float.PositiveInfinity)
          }

        case _ =>
      }
    }

    if (BottomRow.children.nonEmpty) {
      children :+= BottomRow
    }
  })

  override def update(): Unit = {
    super.update()

    if (!disk.editingAllowed) {
      close()
    }
  }
}

object DiskEditWindow {
  trait EditableDisk {
    def disk: Option[Environment]

    def diskAddress: Option[String] = for (
      disk <- disk;
      node <- Option(disk.node);
      address <- Option(node.address)
    ) yield address

    def capacity: Long

    def diskKind: String

    def diskLabel: Option[String]

    def diskLabel_=(label: Option[String]): Unit

    def isLabelWriteable: Boolean

    def editingAllowed: Boolean
  }

  trait HasColor {
    def color: DyeColor

    def color_=(color: DyeColor): Unit
  }

  trait Lockable {
    def lock(): Unit
  }

  trait CanChangeManaged {
    def setManaged(managed: Boolean): Unit
  }
}
