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

import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import org.lwjgl.opengl.GL11
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.Widgets8
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.DockResizeMode
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.SmallEnumRectangleButtonPanel
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.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.panels.util.GridPanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.core.asGetterSetter
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
import ru.dbotthepony.mc.otm.core.util.formatReadableNumber
import ru.dbotthepony.mc.otm.core.util.formatSiComponent
import ru.dbotthepony.mc.otm.menu.storage.ItemMonitorMenu
import ru.dbotthepony.mc.otm.storage.ITEM_STORAGE
import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak

@MouseTweaksDisableWheelTweak
class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Component) :
	MatteryScreen<ItemMonitorMenu>(menu, inventory, title) {

	override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
		val frame = FramePanel(this@ItemMonitorScreen, null, 0f, 0f, 1f, 1f, getTitle())

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

		val topPanel = EditablePanel(this, frame)
		topPanel.height = ITEM_GRID_HEIGHT * 18f
		topPanel.dock = Dock.TOP

		val bottomPanel = EditablePanel(this, frame)
		bottomPanel.height = 3 * 18f
		bottomPanel.dock = Dock.TOP
		bottomPanel.setDockMargin(top = 6f)

		frame.height = topPanel.height + bottomPanel.height + frame.dockPadding.top + frame.dockPadding.bottom + 3f
		frame.width = 178f + frame.dockPadding.left + frame.dockPadding.right

		val viewScrollBar = DiscreteScrollBarPanel(this, topPanel,
												   { integerDivisionDown(menu.networkedItemView.itemCount, ITEM_GRID_WIDTH) },
												   { _, _, _ -> },
												   28f + ITEM_GRID_WIDTH * 18f + 2f, 16f, ITEM_GRID_HEIGHT * 18f)

		viewScrollBar.dock = Dock.RIGHT
		viewScrollBar.setDockMargin(left = 2f)

		val gridPanel = GridPanel(this, topPanel, width = ITEM_GRID_WIDTH * 18f, height = ITEM_GRID_HEIGHT * 18f, columns = ITEM_GRID_WIDTH, rows = ITEM_GRID_HEIGHT)
		gridPanel.dock = Dock.FILL

		for (i in 0 until ITEM_GRID_WIDTH * ITEM_GRID_HEIGHT) {
			object : AbstractSlotPanel<ItemMonitorScreen>(this@ItemMonitorScreen, gridPanel) {
				private val index get() = i + viewScrollBar.scroll * ITEM_GRID_WIDTH

				override val itemStack: ItemStack get() {
					return menu.networkedItemView.sortedView.getOrNull(index)?.stack?.item ?: ItemStack.EMPTY
				}

				override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
					return viewScrollBar.mouseScrolledInner(x, y, scroll)
				}

				override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
					menu.networkedItemView.mouseClick(index, button)
					return true
				}

				override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
					renderSlotBackground(graphics, mouseX, mouseY, partialTick)

					val itemstack = menu.networkedItemView.sortedView.getOrNull(index)?.stack ?: ITEM_STORAGE.empty
					val stack = graphics.pose()

					renderRegular(graphics, itemstack.stack, "")

					if (!itemstack.isEmpty) {
						stack.pushPose()

						val text = itemstack.count.formatSiComponent(decimalPlaces = 1)
						val textWidth = font.width(text)

						stack.translate((width - textWidth * FONT_SCALE).toDouble(), (height - font.lineHeight * FONT_SCALE).toDouble(), 103.0)

						stack.scale(FONT_SCALE, FONT_SCALE, 1f)

						RenderSystem.depthFunc(GL11.GL_ALWAYS)

						graphics.drawString(font, text, 1, 1, 0x0)
						graphics.drawString(font, text, 0, 0, 16777215)

						stack.popPose()
					}
				}

				override fun getItemStackTooltip(stack: ItemStack): List<Component> {
					return super.getItemStackTooltip(stack).also {
						it as MutableList<Component>
						val realStack = menu.networkedItemView.sortedView.getOrNull(index)!!.stack
						it.add(TranslatableComponent("otm.gui.stored_amount", realStack.count.formatReadableNumber()).withStyle(ChatFormatting.DARK_GRAY))
					}
				}
			}
		}

		val craftingGrid = GridPanel(this, bottomPanel, width = 3 * 18f, height = 3 * 18f, columns = 3, rows = 3)
		craftingGrid.dock = Dock.LEFT

		for (i in 0 until 9) {
			SlotPanel(this, craftingGrid, menu.craftingSlots[i])
		}

		val arrowAndButtons = object : EditablePanel<ItemMonitorScreen>(this@ItemMonitorScreen, bottomPanel, width = ProgressGaugePanel.GAUGE_BACKGROUND.width) {
			override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
				ProgressGaugePanel.GAUGE_BACKGROUND.render(graphics, y = height / 2f - ProgressGaugePanel.GAUGE_BACKGROUND.height / 2f)
			}
		}

		arrowAndButtons.dock = Dock.LEFT
		arrowAndButtons.setDockMargin(left = 4f)

		EditablePanel(this, arrowAndButtons, y = 0f, height = 8f, width = arrowAndButtons.width)

		val arrowLine = EditablePanel(this, arrowAndButtons, y = 38f, height = 8f, width = arrowAndButtons.width)

		val refillPriority = SmallEnumRectangleButtonPanel(this, arrowLine,
			enum = ItemMonitorPlayerSettings.IngredientPriority::class.java,
			prop = menu.settings::ingredientPriority.asGetterSetter(watch = { _, _ -> menu.sendSettingsToServer() }),
			defaultValue = ItemMonitorPlayerSettings.IngredientPriority.SYSTEM)

		refillPriority.tooltips.add(TranslatableComponent("otm.gui.item_monitor.refill_source.desc"))
		refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.SYSTEM, tooltip = ItemMonitorPlayerSettings.IngredientPriority.SYSTEM.component, skinElement = Widgets8.WHITE_ARROW_DOWN, winding = UVWindingOrder.FLIP)
		refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.INVENTORY, tooltip = ItemMonitorPlayerSettings.IngredientPriority.INVENTORY.component, skinElement = Widgets8.WHITE_ARROW_DOWN)
		refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.INVENTORY_FIRST, tooltip = ItemMonitorPlayerSettings.IngredientPriority.INVENTORY_FIRST.component, skinElement = Widgets8.ARROW_SIDEWAYS, winding = UVWindingOrder.FLIP)
		refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.SYSTEM_FIRST, tooltip = ItemMonitorPlayerSettings.IngredientPriority.SYSTEM_FIRST.component, skinElement = Widgets8.ARROW_SIDEWAYS)
		refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.DO_NOT, tooltip = ItemMonitorPlayerSettings.IngredientPriority.DO_NOT.component, skinElement = Widgets8.MINUS)

		refillPriority.dock = Dock.LEFT

		val resultAndButtons = EditablePanel(this, bottomPanel, width = 18f)

		resultAndButtons.dock = Dock.LEFT
		resultAndButtons.setDockMargin(left = 6f)

		SlotPanel(this, resultAndButtons, menu.craftingResult, y = 18f)

		val resultTarget = SmallEnumRectangleButtonPanel(this, resultAndButtons, y = 38f,
			enum = ItemMonitorPlayerSettings.ResultTarget::class.java,
			prop = menu.settings::resultTarget.asGetterSetter(watch = { _, _ -> menu.sendSettingsToServer() }),
			defaultValue = ItemMonitorPlayerSettings.ResultTarget.MIXED)

		resultTarget.tooltips.add(TranslatableComponent("otm.gui.item_monitor.result_target.desc"))
		resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.MIXED, tooltip = ItemMonitorPlayerSettings.ResultTarget.MIXED.component, skinElement = Widgets8.ARROW_SIDEWAYS)
		resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.ALL_INVENTORY, tooltip = ItemMonitorPlayerSettings.ResultTarget.ALL_INVENTORY.component, skinElement = Widgets8.ARROW_PAINTED_UP, winding = UVWindingOrder.FLIP)
		resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM, tooltip = ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM.component, skinElement = Widgets8.ARROW_PAINTED_UP)

		val craftingAmount = SmallEnumRectangleButtonPanel(this, resultAndButtons, x = 10f, y = 38f,
			enum = ItemMonitorPlayerSettings.Amount::class.java,
			prop = menu.settings::craftingAmount.asGetterSetter(watch = { _, _ -> menu.sendSettingsToServer() }),
			defaultValue = ItemMonitorPlayerSettings.Amount.STACK)

		craftingAmount.tooltips.add(TranslatableComponent("otm.gui.item_monitor.amount.desc"))
		craftingAmount.add(ItemMonitorPlayerSettings.Amount.ONE, tooltip = ItemMonitorPlayerSettings.Amount.ONE.component, skinElement = Widgets8.ONE)
		craftingAmount.add(ItemMonitorPlayerSettings.Amount.STACK, tooltip = ItemMonitorPlayerSettings.Amount.STACK.component, skinElement = Widgets8.S)
		craftingAmount.add(ItemMonitorPlayerSettings.Amount.FULL, tooltip = ItemMonitorPlayerSettings.Amount.FULL.component, skinElement = Widgets8.F)

		val craftingHistory = GridPanel(this, bottomPanel, width = 3 * 18f, height = 3 * 18f, columns = 3, rows = 3)
		craftingHistory.dock = Dock.LEFT
		craftingHistory.setDockMargin(left = 4f)

		val craftingHistoryScroll = DiscreteScrollBarPanel(this, bottomPanel, { 0 }, { _, _, _ -> })
		craftingHistoryScroll.dock = Dock.LEFT
		craftingHistoryScroll.setDockMargin(left = 2f)

		for (i in 0 until 9) {
			object : AbstractSlotPanel<ItemMonitorScreen>(this@ItemMonitorScreen, craftingHistory) {
				override val itemStack: ItemStack get() {
					return ItemStack(Items.ARROW, 42)
				}

				override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
					return craftingHistoryScroll.mouseScrolledInner(x, y, scroll)
				}
			}
		}

		val leftStrip = BackgroundPanel.padded(this, frame, width = AbstractSlotPanel.SIZE, height = 1f)

		BatterySlotPanel(this, leftStrip, menu.batterySlot).also {
			it.dock = Dock.BOTTOM
			leftStrip.height += it.height
		}

		WidePowerGaugePanel(this, leftStrip, menu.energyWidget).also {
			it.dock = Dock.FILL
			it.dockResize = DockResizeMode.NONE
			leftStrip.height += it.height
		}

		leftStrip.height += 3f

		leftStrip.x = -leftStrip.width - 2f
		leftStrip.y = frame.height - leftStrip.height

		return frame
	}

	companion object {
		const val ITEM_GRID_WIDTH = 9
		const val ITEM_GRID_HEIGHT = 5

		const val FONT_SCALE = 0.6f
	}
}
