package ru.dbotthepony.mc.otm.menu.tech

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.minecraftforge.common.capabilities.ForgeCapabilities
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidStationBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.matteryPlayer
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.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus
import kotlin.reflect.KMutableProperty0

class AndroidStationMenu @JvmOverloads constructor(
	containerID: Int,
	inventory: Inventory,
	tile: AndroidStationBlockEntity? = null
) : MatteryPoweredMenu(MMenus.ANDROID_STATION, containerID, inventory, tile) {
	private fun container(target: (MatteryPlayerCapability) -> KMutableProperty0<ItemStack>): Container {
		if (ply is ServerPlayer)
			return PartContainer(target.invoke(ply.matteryPlayer ?: throw NullPointerException("OTM player capability is missing")))
		else
			return SimpleContainer(1)
	}

	private inner class PartContainer(parent: KMutableProperty0<ItemStack>) : Container {
		private var item by parent

		override fun clearContent() {
			setItem(0, ItemStack.EMPTY)
		}

		override fun getContainerSize(): Int {
			return 1
		}

		override fun isEmpty(): Boolean {
			return item.isEmpty
		}

		override fun getItem(p_18941_: Int): ItemStack {
			if (p_18941_ != 0)
				return ItemStack.EMPTY

			return item
		}

		override fun removeItem(p_18942_: Int, p_18943_: Int): ItemStack {
			if (p_18942_ != 0 || energyWidget.level < AndroidStationBlockEntity.ENERGY_PER_OPERATION || item.isEmpty)
				return ItemStack.EMPTY

			(tile as AndroidStationBlockEntity).energy.extractEnergy(AndroidStationBlockEntity.ENERGY_PER_OPERATION, false)
			return removeItemNoUpdate(p_18942_)
		}

		override fun removeItemNoUpdate(p_18951_: Int): ItemStack {
			if (p_18951_ != 0)
				return ItemStack.EMPTY

			val old = item.copy()
			item = ItemStack.EMPTY
			return old
		}

		override fun setItem(p_18944_: Int, p_18945_: ItemStack) {
			if (p_18944_ != 0)
				return

			(tile as AndroidStationBlockEntity).energy.extractEnergy(AndroidStationBlockEntity.ENERGY_PER_OPERATION, false)
			item = p_18945_
		}

		override fun setChanged() {
			// no op
		}

		override fun stillValid(p_18946_: Player): Boolean {
			return true
		}

		override fun getMaxStackSize(): Int {
			return 1
		}
	}

	private inner class AndroidSlot(container: Container, private val condition: (ItemStack) -> Boolean) : MatterySlot(container, 0) {
		override fun mayPickup(player: Player): Boolean {
			if (tile is AndroidStationBlockEntity) {
				return super.mayPickup(player) && tile.energy.batteryLevel >= AndroidStationBlockEntity.ENERGY_PER_OPERATION
			}

			return super.mayPickup(player) && energyWidget.level >= AndroidStationBlockEntity.ENERGY_PER_OPERATION
		}

		override fun mayPlace(itemStack: ItemStack): Boolean {
			if (tile is AndroidStationBlockEntity) {
				return tile.energy.batteryLevel >= AndroidStationBlockEntity.ENERGY_PER_OPERATION && condition.invoke(itemStack)
			}

			return energyWidget.level >= AndroidStationBlockEntity.ENERGY_PER_OPERATION && condition.invoke(itemStack)
		}
	}

	val androidBattery: MatterySlot = AndroidSlot(container { it.androidEnergy::item }) {
		it.getCapability(ForgeCapabilities.ENERGY).isPresent
	}

	val equipment = makeEquipmentSlots()
	val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
	val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)

	init {
		addInventorySlots()
		addStorageSlot(androidBattery)
	}

	override fun stillValid(player: Player): Boolean {
		return super.stillValid(player) && player.matteryPlayer?.isAndroid == true
	}
}
