@file:Suppress("FunctionName")

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

import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.render.renderRect
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.ISlotPanel
import javax.annotation.Nonnull
import kotlin.math.roundToInt

open class SlotPanel<out S : MatteryScreen<*>, out T : Slot> @JvmOverloads constructor(
	screen: S,
	parent: EditablePanel<*>?,
	final override val slot: T,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = SIZE,
	height: Float = SIZE,
) : AbstractSlotPanel<S>(screen, parent, x, y, width, height), ISlotPanel<T> {
	override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
		screen.returnSlot = slot
		return true
	}

	override fun mouseDraggedInner(x: Double, y: Double, button: Int, xDelta: Double, yDelta: Double): Boolean {
		screen.returnSlot = slot
		return true
	}

	override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
		screen.returnSlot = slot
		return true
	}

	override val itemStack: ItemStack
		get() = slot.item

	override fun visibilityChanges(new: Boolean, old: Boolean) {
		if (!new) {
			slot.x = Int.MAX_VALUE
			slot.y = Int.MAX_VALUE
		}
	}

	override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
		slot.x = absoluteX.roundToInt() - screen.guiLeft
		slot.y = absoluteY.roundToInt() - screen.guiTop
		renderSlotBackground(graphics, mouseX, mouseY, partialTick)

		var itemstack = slot.item
		val carried = screen.menu.carried
		var dragHit = false
		var countOverride: String? = null

		if (!carried.isEmpty && screen.isQuickCrafting && screen.quickCraftSlots.contains(slot)) {
			if (screen.quickCraftSlots.size == 1) {
				return
			}

			if (AbstractContainerMenu.canItemQuickReplace(slot, carried, true) && screen.menu.canDragTo(slot)) {
				itemstack = carried.copy()
				dragHit = true

				val k = Math.min(AbstractContainerMenu.getQuickCraftPlaceCount(
					screen.quickCraftSlots,
					screen.quickCraftingType,
					itemstack
				) + slot.item.count, slot.getMaxStackSize(itemstack))

				if (itemstack.count > k) {
					countOverride = ChatFormatting.YELLOW.toString() + k
					itemstack.count = k
				}
			} else {
				screen.quickCraftSlots.remove(slot)
				screen.recalculateQuickCraftRemaining()
			}
		}

		RenderSystem.setShader(GameRenderer::getPositionTexShader)

		if (dragHit) {
			graphics.renderRect(1f, 1f, width - 1, height - 1, color = SLOT_HIGHLIGHT_DRAG)
		}

		if (itemstack.isEmpty) {
			val icon = slot.noItemIcon

			if (icon != null) {
				val texture = minecraft.getTextureAtlas(icon.first).apply(icon.second)
				RenderSystem.setShaderTexture(0, texture.atlasLocation())
				graphics.blit(1, 1, 0, 16, 16, texture)
			} else {
				slotBackgroundEmpty?.render(graphics, 0f, 0f, width = width, height = height)
			}
		}

		renderRegular(graphics, itemstack, countOverride)

		if (isHovered) {
			screen.hoveredSlot = slot
		}
	}

	override fun innerRenderTooltips(@Nonnull graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
		// no op, screen does it for us (completely)
		return false
	}
}

fun <S : MatteryScreen<*>, T : Slot> BatterySlotPanel(
	screen: S,
	parent: EditablePanel<*>?,
	slot: T,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = AbstractSlotPanel.SIZE,
	height: Float = AbstractSlotPanel.SIZE,
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.BATTERY_SLOT_BACKGROUND }

fun <S : MatteryScreen<*>, T : Slot> EquipmentBatterySlotPanel(
	screen: S,
	parent: EditablePanel<*>?,
	slot: T,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = AbstractSlotPanel.SIZE,
	height: Float = AbstractSlotPanel.SIZE,
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.EQUIPMENT_BATTERY_SLOT_BACKGROUND }

fun <S : MatteryScreen<*>, T : Slot> PatternSlotPanel(
	screen: S,
	parent: EditablePanel<*>?,
	slot: T,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = AbstractSlotPanel.SIZE,
	height: Float = AbstractSlotPanel.SIZE,
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.PATTERN_SLOT_BACKGROUND }

fun <S : MatteryScreen<*>, T : Slot> MatterCapacitorSlotPanel(
	screen: S,
	parent: EditablePanel<*>?,
	slot: T,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = AbstractSlotPanel.SIZE,
	height: Float = AbstractSlotPanel.SIZE,
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.MATTER_CAPACITOR_SLOT_BACKGROUND }
