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

import mezz.jei.api.constants.RecipeTypes
import net.minecraft.client.gui.screens.inventory.InventoryScreen
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.neoforged.neoforge.network.PacketDistributor
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.RenderGravity
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.render.sprites.sprite
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
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.DiscreteScrollBarPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.setMousePos
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
import ru.dbotthepony.mc.otm.network.ExopackMenuOpen
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)

		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 = InventorySlotPanel(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 || menu.capability.isExopackEnderAccessInstalled) {
			val craftingTab = frame.CustomTab()

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

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

		if (menu.capability.isExopackSmeltingInstalled) {
			val tab = frame.CustomTab()

			tab.activeIcon = ItemStackIcon(ItemStack(Items.FURNACE))
			tab.inactiveIcon = tab.activeIcon

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

			tab.onOpen = Runnable { furnaceCanvas.visible = true; menu.furnaceMenuOpenState.accept(true) }
			tab.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

					it.setRecipeType { listOf(RecipeTypes.SMELTING) }
				}

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

		if (menu.capability.isExopackEnderAccessInstalled) {
			val tab = frame.CustomTab()

			tab.activeIcon = ItemStackIcon(ItemStack(Items.ENDER_CHEST))
			tab.inactiveIcon = tab.activeIcon

			val enderCanvas = EditablePanel(this, topLine)
			enderCanvas.dock = Dock.FILL
			enderCanvas.visible = false

			tab.onOpen = Runnable {
				enderCanvas.visible = true
				equipment.visible = false
				menu.enderChestOpenState.accept(true)
			}

			tab.onClose = Runnable {
				enderCanvas.visible = false
				equipment.visible = true
				menu.enderChestOpenState.accept(false)
			}

			val grid = GridPanel.slots(this, enderCanvas, 9, 3)
			grid.gravity = RenderGravity.CENTER_LEFT
			grid.dock = Dock.LEFT

			val enderControls = DeviceControls(this, enderCanvas)
			enderControls.dock = Dock.RIGHT
			enderControls.sortingButtons(menu.sortEnderChest!!, false)
			enderControls.dockTop = 6f

			menu.enderChestSlots.forEach {
				SlotPanel(this, grid, it)
			}
		}

		makeChargePanels(frame)

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

		val closeButtonPanel = ButtonPanel.square18(this, frame, x = frame.width - 2f - 18f, y = -18f - 2f, icon = 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, icon = Widgets18.CURIOS_INVENTORY, onPress = {
				openCuriosScreen(minecraft!!.player!!.containerMenu.carried)
			}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_curios")) }
		}
		*/

		val controls = DeviceControls(this, frame)

		controls.dockTop = 85f

		controls.addButton(makeInventoryRowsControls(frame) { movePixels ->
			frame.y += movePixels
			moveMousePosScaled(y = movePixels)
		} as EditablePanel<ExopackInventoryScreen>)

		if (menu.sortInventoryInput != null) {
			controls.sortingButtons(menu.sortInventoryInput!!)
		}

		var x = -4f

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

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

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

		return frame
	}

	init {
		menu.enderChestOpenState.value = false
		menu.furnaceMenuOpenState.value = false
		PacketDistributor.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
	}
}
