package ru.dbotthepony.mc.otm.block.entity.tech

import net.minecraft.core.BlockPos
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.capability.moveMatter
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities

class MatterHatchBlockEntity(
	val isInput: Boolean,
	type: BlockEntityType<*>,
	blockPos: BlockPos,
	blockState: BlockState
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
	val container = object : MatteryContainer(::markDirtyFast, CAPACITY) {
		override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
			return 1
		}
	}.also(::addDroppableContainer)

	val matter = ProfiledMatterStorage(MatterStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), MachinesConfig::MATTER_HATCH))

	val itemHandler = if (isInput) {
		container.handler(HandlerFilter.MatterProviders)
	} else {
		container.handler(HandlerFilter.MatterConsumers)
	}

	init {
		savetables.stateful(::container, INVENTORY_KEY)
		savetables.stateful(::matter, MATTER_STORAGE_KEY)

		// it would cause a lot of frustration if hatches accept stuff only though one face
		exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
		exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
	}

	override fun tick() {
		super.tick()

		if (!redstoneControl.isBlockedByRedstone && matter.missingMatter > Decimal.ZERO) {
			container.forEach {
				it.getCapability(MatteryCapability.MATTER_ITEM)?.let {
					if (isInput) {
						moveMatter(it, matter, simulate = false)
					} else {
						moveMatter(matter, it, simulate = false)
					}
				}
			}
		}
	}

	override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
		return MatterHatchMenu(isInput, containerID, inventory, this)
	}

	companion object {
		const val CAPACITY = 1

		val INPUT_TAG = BlockEntityTag(MatterHatchBlockEntity::class) { it.isInput }
		val OUTPUT_TAG = BlockEntityTag(MatterHatchBlockEntity::class) { !it.isInput }

		fun input(blockPos: BlockPos, blockState: BlockState): MatterHatchBlockEntity {
			return MatterHatchBlockEntity(true, MBlockEntities.MATTER_INPUT_HATCH, blockPos, blockState)
		}

		fun output(blockPos: BlockPos, blockState: BlockState): MatterHatchBlockEntity {
			return MatterHatchBlockEntity(false, MBlockEntities.MATTER_OUTPUT_HATCH, blockPos, blockState)
		}
	}
}
