package ru.dbotthepony.mc.otm.container

import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraftforge.items.IItemHandler

class ContainerHandler @JvmOverloads internal constructor(
	private val container: MatteryContainer,
	private val filter: HandlerFilter = HandlerFilter.Both,
) : IItemHandler {
	override fun getSlots() = container.containerSize
	override fun getStackInSlot(slot: Int) = container[slot]

	override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
		if (!container.testSlotFilter(slot, stack) || !filter.canInsert(slot, stack))
			return stack

		filter.preInsert(slot, stack, simulate)
		val localStack = container[slot]

		if (localStack.isEmpty) {
			if (!simulate) {
				container.setItem(slot, stack.copyWithCount(stack.count.coerceAtMost(stack.maxStackSize).coerceAtMost(container.getMaxStackSize(slot))))
			}

			if (stack.count <= container.getMaxStackSize(slot).coerceAtMost(stack.maxStackSize)) {
				return ItemStack.EMPTY
			} else {
				return stack.copyWithCount(container.getMaxStackSize(slot))
			}
		} else if (localStack.isStackable && localStack.maxStackSize.coerceAtMost(container.getMaxStackSize(slot)) > localStack.count && ItemStack.isSameItemSameTags(localStack, stack)) {
			val newCount = localStack.maxStackSize.coerceAtMost(localStack.count + stack.count).coerceAtMost(container.getMaxStackSize(slot))
			val diff = newCount - localStack.count

			if (diff != 0) {
				if (!simulate) {
					localStack.grow(diff)
					container.setChanged(slot)
				}

				val copy = stack.copy()
				copy.shrink(diff)
				return copy
			}
		}

		return stack
	}

	override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack {
		if (amount <= 0 || container.isSlotForbiddenForAutomation(slot))
			return ItemStack.EMPTY

		filter.preExtract(slot, amount, simulate)

		val localStack = container.getItem(slot)
		if (localStack.isEmpty) return ItemStack.EMPTY
		if (!filter.canExtract(slot, amount, localStack)) return ItemStack.EMPTY

		val minimal = amount.coerceAtMost(localStack.count)
		val copy = localStack.copy()
		copy.count = minimal

		if (!simulate) {
			localStack.shrink(minimal)
			container.setChanged(slot)
		}

		return copy
	}

	override fun getSlotLimit(slot: Int): Int {
		return container.maxStackSize
	}

	override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
		return container.testSlotFilter(slot, stack) && filter.canInsert(slot, stack)
	}
}
