package ocelot.desktop.windows

import ocelot.desktop.ColorScheme
import ocelot.desktop.audio.{ClickSoundSourceFactory, SoundSource}
import ocelot.desktop.color.Color
import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D}
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.inventory.item.{NetworkCardItem, ServerItem}
import ocelot.desktop.node.nodes.RackNode
import ocelot.desktop.ui.layout.{Layout, LinearLayout}
import ocelot.desktop.ui.widget._
import ocelot.desktop.ui.widget.slot.RackMountableSlotWidget
import ocelot.desktop.ui.widget.traits.HoverHighlight
import ocelot.desktop.ui.widget.window.PanelWindow
import ocelot.desktop.util.Orientation
import totoro.ocelot.brain.util.Direction
import totoro.ocelot.brain.util.Direction.Direction

class RackWindow(rackNode: RackNode) extends PanelWindow {
  private val linesMarginLeft = 12
  private val linesGap = 4
  private val lineSideHeight = 6
  private val lineNetworkHeight = 4

  private val nodeButtonsGap = 12
  private val nodeButtonsWidth = 10

  private def shouldConnectionBeVisible(slotWidget: RackMountableSlotWidget, connectableIndex: Int) = {
    connectableIndex == 0 ||
    (
      slotWidget.item match {
        case Some(serverItem: ServerItem) =>
          val item = serverItem.Slot(connectableIndex).get
          item.isDefined && item.get.isInstanceOf[NetworkCardItem]

        case _ => false
      }
    )
  }

  override protected def title: String = "Rack"

  private val mountableSlotWidgets: Array[RackMountableSlotWidget] =
    new Array[RackMountableSlotWidget](rackNode.rack.getSizeInventory)

  setInner(
    new PaddingBox(
      // Slots & lines
      new Widget {
        override protected val layout: Layout = new LinearLayout(this)

        // Slots
        children :+= new PaddingBox(
          new Widget {
            override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical, gap = 4)

            var widget: RackMountableSlotWidget = _

            for (i <- mountableSlotWidgets.indices) {
              widget = new RackMountableSlotWidget(rackNode.Slot(i))
              mountableSlotWidgets(i) = widget
              children :+= widget
            }
          },
          Padding2D(top = 8),
        )

        // Lines & connections
        children :+= new Widget {
          override def minimumSize: Size2D = Size2D(146, 182)
          override def maximumSize: Size2D = minimumSize

          override def draw(g: Graphics): Unit = {
            // Relay mode line
            if (rackNode.rack.isRelayEnabled) {
              g.sprite(IconSource.Window.Rack.Network.Connector, position.x + 12, position.y + 172, 102, 4)
            }

            // Lines background
            g.sprite(IconSource.Window.Rack.Lines, position.x + linesMarginLeft, position.y, size.width, size.height)

            super.draw(g)
          }

          // Connection rows
          children :+= new PaddingBox(
            new Widget {
              override protected val layout: Layout =
                new LinearLayout(this, orientation = Orientation.Vertical, gap = 10)

              for (i <- mountableSlotWidgets.indices) {
                val mountableIndex = i
                val mountableSlotWidget = mountableSlotWidgets(mountableIndex)

                // Rows
                children :+= new Widget {
                  override def minimumSize: Size2D = Size2D(112, 30)

                  override def maximumSize: Size2D = minimumSize

                  override def draw(g: Graphics): Unit = {
                    if (mountableSlotWidget.item.isEmpty)
                      return

                    var y = position.y
                    var connectionHeight: Float = 0

                    for (connectableIndex <- 0 until 4) {
                      connectionHeight = if (connectableIndex == 0) lineSideHeight else lineNetworkHeight

                      if (shouldConnectionBeVisible(mountableSlotWidget, connectableIndex)) {
                        val connection = rackNode.rack.nodeMapping(mountableIndex)(connectableIndex)
                        val source = if (connectableIndex == 0) {
                          IconSource.Window.Rack.Side
                        } else {
                          IconSource.Window.Rack.Network
                        }

                        // Connector
                        g.sprite(source.Connector, position.x, y, 2, connectionHeight)

                        // Line
                        for (connection <- connection) {
                          g.sprite(
                            source.DirectionIcon(connection),
                            position.x + 2,
                            y,
                            connection match {
                              case Direction.Bottom => nodeButtonsGap
                              case Direction.Top => nodeButtonsGap * 2 + nodeButtonsWidth
                              case Direction.Back => nodeButtonsGap * 3 + nodeButtonsWidth * 2
                              case Direction.Right => nodeButtonsGap * 4 + nodeButtonsWidth * 3
                              case _ => nodeButtonsGap * 5 + nodeButtonsWidth * 4
                            },
                            connectionHeight,
                          )
                        }
                      }

                      y += connectionHeight + linesGap
                    }

                    super.draw(g)
                  }

                  // Node buttons holder
                  children :+= new PaddingBox(
                    new Widget {
                      override protected val layout: Layout = new LinearLayout(this, gap = nodeButtonsGap)

                      def addSideButtons(direction: Direction): Unit = {
                        children :+= new Widget {
                          override protected val layout: Layout =
                            new LinearLayout(this, orientation = Orientation.Vertical, gap = linesGap)

                          for (i <- 0 until 4) {
                            val connectableIndex = i
                            val isNetwork = connectableIndex > 0

                            children :+= new Button with HoverHighlight {
                              override def enabled: Boolean =
                                shouldConnectionBeVisible(mountableSlotWidget, connectableIndex)

                              override protected def highlightBounds: Rect2D = bounds.inflated(-2, 0)

                              override def minimumSize: Size2D = Size2D(
                                nodeButtonsWidth,
                                if (isNetwork) lineNetworkHeight else lineSideHeight,
                              )

                              override def maximumSize: Size2D = minimumSize

                              override def onClick(): Unit = {
                                val oldConnection = rackNode.rack.nodeMapping(mountableIndex)(connectableIndex)

                                rackNode.rack.connect(
                                  mountableIndex,
                                  connectableIndex - 1,
                                  Option.unless(oldConnection.contains(direction))(direction),
                                )
                              }

                              override def draw(g: Graphics): Unit = {
                                if (enabled) {
                                  g.sprite(IconSource.Window.Rack.Node.DirectionIcon(direction), bounds)
                                  drawHighlight(g)
                                }
                              }
                            }
                          }
                        }
                      }

                      addSideButtons(Direction.Bottom)
                      addSideButtons(Direction.Top)
                      addSideButtons(Direction.Back)
                      addSideButtons(Direction.Right)
                      addSideButtons(Direction.Left)
                    },
                    Padding2D(left = 14),
                  )
                }
              }
            },
            Padding2D(10),
          )
        }

        // Lines description
        children :+= new PaddingBox(
          new Widget {
            override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical)

            def addLabel(data: String): Unit = {
              children :+= new PaddingBox(
                new Label {
                  override def text: String = data
                },
                Padding2D(left = 20, bottom = 6),
              )
            }

            addLabel("Bottom")
            addLabel("Top")
            addLabel("Back")
            addLabel("Right")
            addLabel("Left")

            // Relay enable button
            children :+= new PaddingBox(
              new IconButton(
                IconSource.Buttons.RackRelayOff,
                IconSource.Buttons.RackRelayOn,
                mode = IconButton.Mode.Switch,
                sizeMultiplier = 2,
                model = IconButton.ReadOnlyModel(rackNode.rack.isRelayEnabled),
              ) with HoverHighlight {
                override def onPressed(): Unit = rackNode.rack.isRelayEnabled = true
                override def onReleased(): Unit = rackNode.rack.isRelayEnabled = false

                override def draw(g: Graphics): Unit = {
                  super.draw(g)

                  val x = position.x + 38
                  val y = position.y + size.height / 2 - 8
                  val text = if (rackNode.rack.isRelayEnabled) "Enabled" else "Disabled"

                  g.background = Color.Transparent

                  // Shadow
                  g.foreground = Color.Black
                  g.text(x + 2, y + 1, text)

                  // Text itself
                  g.foreground = ColorScheme("RackRelayButtonText")
                  g.text(x, y, text)
                }

                override protected def clickSoundSource: ClickSoundSourceFactory = SoundSource.MinecraftClick
              },
              Padding2D(left = -15, top = 45),
            )
          },
          Padding2D(top = 3),
        )
      },
      Padding2D(
        top = 8,
        right = 8,
        bottom = 8,
        left = 8,
      ),
    )
  )
}
