package ru.dbotthepony.mc.otm.menu.matter

import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.Container
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingInput
import ru.dbotthepony.mc.otm.block.entity.matter.MatterEntanglerBlockEntity
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.item.IQuantumLinked
import ru.dbotthepony.mc.otm.menu.OutputSlot
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.makeSlots
import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.TakeExperienceWidget
import ru.dbotthepony.mc.otm.registry.game.MMenus
import ru.dbotthepony.mc.otm.registry.game.MRecipes
import java.util.*

class MatterEntanglerMenu(
	containerId: Int, inventory: Inventory, tile: MatterEntanglerBlockEntity? = null
) : MatteryPoweredMenu(MMenus.MATTER_ENTANGLER, containerId, inventory, tile) {
	val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
	val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
	val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy)
	val profiledMatter = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter))

	val progress = ProgressGaugeWidget(this, tile?.jobEventLoops?.get(0))

	val inputs: List<MatterySlot> = makeSlots(tile?.inputs ?: object : MatteryCraftingContainer(3, 3) {
		override fun getMaxStackSize(): Int {
			return 1
		}
	}) { it, i ->
		object : MatterySlot(it, i) {
			override fun mayPlace(itemStack: ItemStack): Boolean {
				val list = it.toList()
				list[i] = itemStack
				val shadow = CraftingInput.ofPositioned(3, 3, list)
				val level = player.level()

				return super.mayPlace(itemStack) && (level ?: return false)
					.recipeManager
					.byType(MRecipes.MATTER_ENTANGLER)
					.any { it.value.preemptivelyMatches(shadow, level, 3, 3) }
			}
		}
	}

	val outputs = makeSlots(tile?.output ?: SimpleContainer(1)) { a, b -> OutputSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } }
	val upgrades = makeUpgradeSlots(3, tile?.upgrades)
	val experience = TakeExperienceWidget(this, tile?.experience)

	private val entangling: Container = if (tile == null) object : SimpleContainer(2) {
		override fun getMaxStackSize(): Int {
			return 1
		}
	} else object : MatteryContainer(::rescan, 2) {
		override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
			return 1
		}
	}

	private fun rescan() {
		if (player is ServerPlayer && entangling[0].item is IQuantumLinked && entangling[1].item == entangling[0].item && entangling[0].isNotEmpty && entangling[1].isNotEmpty) {
			val result = (entangling[0].item as IQuantumLinked).merge(entangling[0], entangling[1])
			entanglingC.container[0] = result
		} else if (player is ServerPlayer) {
			entanglingC.container[0] = ItemStack.EMPTY
		}
	}

	private inner class EntanglingInputSlot(index: Int) : MatterySlot(entangling, index) {
		override fun mayPlace(itemStack: ItemStack): Boolean {
			return super.mayPlace(itemStack) && itemStack.item is IQuantumLinked
		}
	}

	val entanglingA: MatterySlot = EntanglingInputSlot(0)
	val entanglingB: MatterySlot = EntanglingInputSlot(1)
	val entanglingC: MatterySlot = object : MatterySlot(MatteryContainer(1), 0) {
		override fun mayPlace(itemStack: ItemStack): Boolean {
			return false
		}

		override fun canTakeItemForPickAll(): Boolean {
			return false
		}

		override fun tryRemove(p_150642_: Int, p_150643_: Int, p_150644_: Player): Optional<ItemStack> {
			rescan()
			return super.tryRemove(p_150642_, p_150643_, p_150644_)
		}

		override fun onTake(p_150645_: Player, p_150646_: ItemStack) {
			if (p_150646_.isNotEmpty) {
				entangling.removeItem(0, 1)
				entangling.removeItem(1, 1)
			}

			super.onTake(p_150645_, p_150646_)
		}
	}

	override fun removed(p_38940_: Player) {
		super.removed(p_38940_)
		clearContainer(p_38940_, entangling)
	}

	init {
		addSlot(outputs)
		addSlot(entanglingA)
		addSlot(entanglingB)
		addSlot(entanglingC)
		mapQuickMoveToInventory(entanglingA)
		mapQuickMoveToInventory(entanglingB)
		mapQuickMoveToInventory(entanglingC)
		outputs.forEach(::mapQuickMoveToInventory)
		addStorageSlot(inputs)
		addInventorySlots()
	}
}
