package ru.dbotthepony.mc.otm.client.screen

import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.client.gui.screens.inventory.InventoryScreen
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import ru.dbotthepony.mc.otm.client.mousePos
import ru.dbotthepony.mc.otm.client.moveMousePosScaled
import ru.dbotthepony.mc.otm.client.render.ItemStackIcon
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.render.sprite
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.BackgroundPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
import ru.dbotthepony.mc.otm.client.screen.widget.HorizontalPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.setMousePos
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded
import ru.dbotthepony.mc.otm.compat.curios.openCuriosScreen
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
import ru.dbotthepony.mc.otm.network.ExoPackMenuOpen
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak

@MouseTweaksDisableWheelTweak
class ExoPackInventoryScreen(menu: ExoPackInventoryMenu) : MatteryScreen<ExoPackInventoryMenu>(menu, TranslatableComponent("otm.gui.exopack")) {
	private lateinit var mainInventoryLine: EditablePanel<ExoPackInventoryScreen>
	private lateinit var scrollPanel: DiscreteScrollBarPanel<ExoPackInventoryScreen>

	override fun updateInventoryRows(old: Int) {
		mainFrame!!.height = FRAME_BASE_HEIGHT + inventoryRows * AbstractSlotPanel.SIZE
		mainInventoryLine.height = AbstractSlotPanel.SIZE * inventoryRows

		for (i in scrollPanel.scroll + inventoryRows until scrollPanel.scroll + old) {
			getInventorySlotsRow(i).visible = false
		}

		for (i in scrollPanel.scroll until scrollPanel.scroll + inventoryRows) {
			getInventorySlotsRow(i).also {
				it.parent = mainInventoryLine
				it.y = AbstractSlotPanel.SIZE * (i - scrollPanel.scroll)
				it.visible = true
			}
		}

		scrollPanel.scroll = scrollPanel.scroll
	}

	override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
		val frame = FramePanel(this, width = 200f, height = FRAME_BASE_HEIGHT + inventoryRows * AbstractSlotPanel.SIZE, title = this.title)

		frame.makeCloseButton()
		frame.onClose { onClose() }

		frame.makeHelpButton().addSlotFiltersHelp().tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))

		val hotbarStrip = EditablePanel(this, frame, height = 18f)
		hotbarStrip.dock = Dock.BOTTOM

		hotbarStrip.setDockMargin(top = 3f)

		scrollPanel = DiscreteScrollBarPanel(this, null, maxScroll = { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) },
			scrollCallback = {
					_, old, new ->

				for (i in old until old + inventoryRows) {
					getInventorySlotsRow(i).visible = false
				}

				for (i in new until new + inventoryRows) {
					val row = getInventorySlotsRow(i)
					row.visible = true
					row.y = (i - new) * AbstractSlotPanel.SIZE
					row.parent = mainInventoryLine
				}

				lastScroll = new
			})

		mainInventoryLine = object : EditablePanel<ExoPackInventoryScreen>(this@ExoPackInventoryScreen, frame, height = AbstractSlotPanel.SIZE * inventoryRows) {
			override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
				return scrollPanel.mouseScrolledInner(x, y, scroll)
			}
		}

		scrollPanel.scroll = lastScroll
		scrollPanel.parent = mainInventoryLine

		mainInventoryLine.dock = Dock.BOTTOM

		for (slot in menu.playerHotbarSlots) {
			InventorySlotPanel(this, hotbarStrip, slot).also {
				it.dock = Dock.LEFT
			}
		}

		val offhand = SlotPanel(this, hotbarStrip, menu.offhandSlot)
		offhand.dock = Dock.RIGHT

		for (i in scrollPanel.scroll until scrollPanel.scroll + inventoryRows) {
			getInventorySlotsRow(i).also {
				it.parent = mainInventoryLine
				it.y = AbstractSlotPanel.SIZE * (i - scrollPanel.scroll)
			}
		}

		val topLine = EditablePanel(this, frame, height = PlayerEquipmentPanel.HEIGHT)
		topLine.dock = Dock.TOP
		topLine.setDockMargin(top = 3f)

		val equipment = PlayerEquipmentPanel(this, topLine, armorSlots = menu.armorSlots)
		equipment.dock = Dock.LEFT
		equipment.setDockMargin(right = 3f)

		val craftingCanvas = EditablePanel(this, topLine, width = 90f)
		craftingCanvas.dock = Dock.LEFT

		val craftingSlotsCanvas = EditablePanel(this, craftingCanvas)

		if (menu.capability.isExoPackCraftingUpgraded) {
			craftingSlotsCanvas.setSize(54f, 54f)

			for (row in 0 .. 2) {
				for (column in 0 .. 2) {
					SlotPanel(this, craftingSlotsCanvas, menu.craftingSlots[row * 3 + column], x = column * 18f, y = row * 18f)
				}
			}
		} else {
			craftingSlotsCanvas.setSize(36f, 36f)

			SlotPanel(this, craftingSlotsCanvas, menu.craftingSlots[0])
			SlotPanel(this, craftingSlotsCanvas, menu.craftingSlots[1], x = 18f)
			SlotPanel(this, craftingSlotsCanvas, menu.craftingSlots[2], y = 18f)
			SlotPanel(this, craftingSlotsCanvas, menu.craftingSlots[3], x = 18f, y = 18f)
		}

		craftingSlotsCanvas.y = topLine.height / 2f - craftingSlotsCanvas.height / 2f

		val resultPanel = SlotPanel(this, craftingCanvas, menu.craftingResultSlot, x = craftingCanvas.width - 18f, y = topLine.height / 2f - 9f)

		SpritePanel(this, craftingCanvas, CRAFT_ARROW, x = craftingSlotsCanvas.width,
					width = craftingCanvas.width - resultPanel.width - craftingSlotsCanvas.width,
					height = topLine.height, centerSprite = true)

		if (menu.capability.isExoPackSmeltingInstalled) {
			val craftingTab = frame.Tab()
			val furnaceTab = frame.Tab()

			craftingTab.activeIcon = ItemStackIcon(ItemStack(Items.CRAFTING_TABLE))
			craftingTab.inactiveIcon = craftingTab.activeIcon
			furnaceTab.activeIcon = ItemStackIcon(ItemStack(Items.FURNACE))
			furnaceTab.inactiveIcon = furnaceTab.activeIcon

			craftingTab.onOpen = Runnable { craftingCanvas.visible = true }
			craftingTab.onClose = Runnable { craftingCanvas.visible = false }

			val furnaceCanvas = EditablePanel(this, topLine, width = 90f)
			furnaceCanvas.dock = Dock.LEFT
			furnaceCanvas.visible = false

			furnaceTab.onOpen = Runnable { furnaceCanvas.visible = true; menu.furnaceMenuOpenState.accept(true) }
			furnaceTab.onClose = Runnable { furnaceCanvas.visible = false; menu.furnaceMenuOpenState.accept(false) }

			for (i in menu.capability.smelters.indices) {
				val row = EditablePanel(this, furnaceCanvas, height = AbstractSlotPanel.SIZE)
				row.dock = Dock.TOP
				row.dockTop = 4f

				SlotPanel(this, row, menu.furnaceInputs[i]).also {
					it.dock = Dock.LEFT
					it.dockLeft = 12f
					it.dockResize = DockResizeMode.NONE
				}

				ProgressGaugePanel(this, row, menu.furnaceProgress[i]).also {
					it.dock = Dock.LEFT
					it.dockLeft = 9f
					it.dockResize = DockResizeMode.NONE
				}

				SlotPanel(this, row, menu.furnaceOutputs[i]).also {
					it.dock = Dock.LEFT
					it.dockLeft = 10f
					it.dockResize = DockResizeMode.NONE
				}
			}

			if (menu.furnaceMenuOpenState.get()) {
				furnaceTab.onClick(InputConstants.MOUSE_BUTTON_LEFT)
			}
		}

		val chargeWidth = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + AbstractSlotPanel.SIZE + 6f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f
		val chargeStrip = BackgroundPanel.paddedCenter(this, frame, frame.width - chargeWidth - 6f, frame.height + 2f, chargeWidth, AbstractSlotPanel.SIZE)
		val chargeStrip2 = BackgroundPanel.paddedCenter(this, frame, frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f, AbstractSlotPanel.SIZE, AbstractSlotPanel.SIZE * 4f)

		chargeStrip.customDock { chargeStrip.setPos(frame.width - chargeWidth - 6f, frame.height + 2f) }
		chargeStrip2.customDock { chargeStrip2.setPos(frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f) }

		BatterySlotPanel(this, chargeStrip, menu.exoPackPowerSlot).also {
			it.dock = Dock.LEFT
		}

		SpritePanel(this, chargeStrip, ProgressGaugePanel.GAUGE_BACKGROUND).also {
			it.dock = Dock.LEFT
			it.dockLeft = 2f
			it.dockResize = DockResizeMode.NONE
		}

		TallHorizontalProfiledPowerGaugePanel(this, chargeStrip, menu.exoPackPower).also {
			it.dock = Dock.LEFT
			it.dockLeft = 2f
		}

		SpritePanel(this, chargeStrip, ProgressGaugePanel.GAUGE_BACKGROUND).also {
			it.dock = Dock.LEFT
			it.dockLeft = 2f
			it.dockResize = DockResizeMode.NONE
		}

		for (slot in menu.exoPackChargeSlots) {
			SlotPanel(this, chargeStrip2, slot).also {
				it.dock = Dock.BOTTOM
				it.slotBackground = Widgets18.CHARGE_SLOT_BACKGROUND
			}
		}

		scrollPanel.dock = Dock.RIGHT
		scrollPanel.setDockMargin(right = 3f)

		val closeButtonPanel = LargeRectangleButtonPanel(this, frame, x = frame.width - 2f - LargeRectangleButtonPanel.SIZE, y = -LargeRectangleButtonPanel.SIZE - 2f, skinElement = Widgets18.RETURN_ARROW_LEFT, onPress = {
			shouldOpenVanillaInventory = true
			val minecraft = minecraft!!

			val (mouseX, mouseY) = mousePos

			onClose()
			minecraft.setScreen(InventoryScreen(minecraft.player!!))

			setMousePos(mouseX, mouseY)
		}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_back")) }

		if (isCuriosLoaded) {
			LargeRectangleButtonPanel(this, frame, x = closeButtonPanel.x - 2f - LargeRectangleButtonPanel.SIZE, y = closeButtonPanel.y, skinElement = Widgets18.CURIOS_INVENTORY, onPress = {
				openCuriosScreen(minecraft!!.player!!.containerMenu.carried)
			}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_curios")) }
		}

		makeInventoryRowsControls(frame, frame.width + 2f, frame.height.coerceAtMost(95f)) { movePixels ->
			frame.y += movePixels
			moveMousePosScaled(y = movePixels)
		}

		var x = -4f

		if (menu.curiosSlots.isNotEmpty()) {
			val curios = makeCuriosPanel(this, frame, menu.curiosSlots)!!

			x -= curios.width
			curios.x = x
		}

		EffectListPanel(this, frame, menu.ply, x - 56f, gridHeight = 6).tick()

		return frame
	}

	init {
		MatteryPlayerNetworkChannel.sendToServer(ExoPackMenuOpen)
		ru.dbotthepony.mc.otm.client.minecraft.player?.containerMenu = menu
	}

	companion object {
		val ENTITY_RECTANGLE = INVENTORY_LOCATION.sprite(25f, 7f, 51f, 72f)
		val CRAFT_ARROW = INVENTORY_LOCATION.sprite(135f, 29f, 16f, 13f)

		const val FRAME_BASE_HEIGHT = 126f
	}
}
