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

import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.client.extensions.common.IClientItemExtensions
import ru.dbotthepony.mc.otm.client.isCtrlDown
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.playGuiClickSound
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.core.GetterSetter
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.menu.UserFilteredSlot

abstract class UserFilteredSlotPanel<out S : MatteryScreen<*>, out T : Slot>(
	screen: S,
	parent: EditablePanel<*>?,
	slot: T,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = SIZE,
	height: Float = SIZE,
) : SlotPanel<S, T>(screen, parent, slot, x, y, width, height) {
	abstract var slotFilter: Item?

	protected open fun renderBackgroundBeforeFilter(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {}

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

		renderBackgroundBeforeFilter(graphics, mouseX, mouseY, partialTick)

		if (slotFilter != null) {
			if (slotFilter !== Items.AIR) {
				val itemStack = ItemStack(slotFilter!!, 1)

				screen.renderItemStack(graphics, itemStack, null)
				clearDepth(graphics)

				graphics.renderRect(0f, 0f, width, height, color = SLOT_FILTER_COLOR)
			} else {
				graphics.renderRect(0f, 0f, width, height, color = SLOT_BLOCK_COLOR)
			}
		}
	}

	override fun innerRenderTooltips(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
		if (isHovered && slotFilter != null && slotFilter !== Items.AIR && itemStack.isEmpty) {
			val itemstack = ItemStack(slotFilter!!, 1)

			graphics.renderComponentTooltip(
				IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: font,
				getItemStackTooltip(itemstack).toMutableList().also {
					it.add(0, TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY))
					it.add(1, TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY))
					it.add(2, TextComponent(""))
				},
				mouseX.toInt(),
				mouseY.toInt(),
				itemstack
			)
		} else if (isHovered && slotFilter === Items.AIR && itemStack.isEmpty) {
			graphics.renderComponentTooltip(
				font,
				ArrayList<Component>().also {
					it.add(TranslatableComponent("otm.gui.slot_filter.forbidden").withStyle(ChatFormatting.GRAY))
					it.add(TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY))
				},
				mouseX.toInt(),
				mouseY.toInt()
			)
		}

		return super.innerRenderTooltips(graphics, mouseX, mouseY, partialTick)
	}

	override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
		if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) {
			if (slotFilter === null) {
				if (screen.menu.carried.isEmpty) {
					slotFilter = slot.item.item
				} else {
					slotFilter = screen.menu.carried.item
				}
			} else {
				slotFilter = null
			}

			playGuiClickSound()

			return true
		} else {
			return super.mouseClickedInner(x, y, button)
		}
	}

	override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
		if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) {
			return true
		}

		return super.mouseReleasedInner(x, y, button)
	}

	companion object {
		val SLOT_FILTER_COLOR = RGBAColor(85, 113, 216, 150)
		val SLOT_BLOCK_COLOR = RGBAColor(219, 113, 113, 150)

		fun <S : MatteryScreen<*>, T : Slot> of(
			screen: S,
			parent: EditablePanel<*>?,
			slot: T,
			x: Float = 0f,
			y: Float = 0f,
			width: Float = SIZE,
			height: Float = SIZE,
			filter: GetterSetter<Item?>
		): UserFilteredSlotPanel<S, T> {
			return object : UserFilteredSlotPanel<S, T>(screen, parent, slot, x, y, width, height) {
				override var slotFilter: Item? by filter
			}
		}

		fun <S : MatteryScreen<*>, T : UserFilteredSlot> of(
			screen: S,
			parent: EditablePanel<*>?,
			slot: T,
			x: Float = 0f,
			y: Float = 0f,
			width: Float = SIZE,
			height: Float = SIZE,
		): UserFilteredSlotPanel<S, T> {
			return object : UserFilteredSlotPanel<S, T>(screen, parent, slot, x, y, width, height) {
				override var slotFilter: Item?
					get() = slot.filter?.get()
					set(value) { slot.filter?.accept(value) }
			}
		}
	}
}
