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

import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
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.Block
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.block.storage.DriveViewerBlock
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
import ru.dbotthepony.mc.otm.menu.storage.DriveViewerMenu
import java.util.UUID

class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_VIEWER, blockPos, blockState) {
	override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER))
	val energyConfig = ConfigurableEnergy(energy)

	val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 1) {
		override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
			super.setChanged(slot, new, old)

			val level = level

			if (level is ServerLevel) {
				tickList.once {
					val isPresent = new.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null
					var state = this@DriveViewerBlockEntity.blockState.setValue(DriveViewerBlock.DRIVE_PRESENT, isPresent)

					if (!isPresent) {
						state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE)
					} else if (energy.batteryLevel >= Decimal.TEN && !redstoneControl.isBlockedByRedstone) {
						state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING)
					}

					if (state !== this@DriveViewerBlockEntity.blockState) {
						level.setBlock(this@DriveViewerBlockEntity.blockPos, state, Block.UPDATE_CLIENTS)
					}
				}
			}
		}
	}.also(::addDroppableContainer)

	interface ISettings {
		var sorting: ItemStorageStackSorter
		var isAscending: Boolean
	}

	inner class Settings : ISettings {
		override var sorting: ItemStorageStackSorter = ItemStorageStackSorter.DEFAULT
			set(value) {
				field = value
				markDirtyFast()
			}

		override var isAscending: Boolean = true
			set(value) {
				field = value
				markDirtyFast()
			}
	}

	val settings = Object2ObjectOpenHashMap<UUID, Settings>()

	fun getSettingsFor(player: Player): ISettings {
		return settings.computeIfAbsent(player.uuid, Object2ObjectFunction { Settings() })
	}

	private fun energyUpdated() {
		val state = blockState.setValue(WorkerState.SEMI_WORKER_STATE, if (energy.batteryLevel >= Decimal.TEN && !redstoneControl.isBlockedByRedstone && blockState[DriveViewerBlock.DRIVE_PRESENT]) WorkerState.WORKING else WorkerState.IDLE)

		if (state != blockState) {
			level?.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
		} else {
			markDirtyFast()
		}
	}

	init {
		savetables.stateful(::energy, ENERGY_KEY)
		savetables.stateful(::container, INVENTORY_KEY)
	}

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