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

import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.AABB
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.capability.moveEnergy
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.otmRandom
import ru.dbotthepony.mc.otm.core.shuffle
import ru.dbotthepony.mc.otm.core.util.countingLazy
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities

class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider {
	override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
		return AndroidStationMenu(containerID, inventory, this)
	}

	private val workerState by countingLazy(blockStateChangesCounter) {
		blockState.getValue(WorkerState.SEMI_WORKER_STATE)
	}

	override val energy: ProfiledEnergyStorage<WorkerEnergyStorage> = ProfiledEnergyStorage(object : WorkerEnergyStorage(::markDirtyFast, MachinesConfig.AndroidStation.VALUES) {
		override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
			return super.extractEnergy(howMuch, simulate).also {
				if (!simulate && this.batteryLevel.isZero) {
					if (workerState != WorkerState.IDLE) {
						level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
					}
				}
			}
		}

		override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
			return super.receiveEnergy(howMuch, simulate).also {
				if (!simulate && it.isPositive) {
					if (workerState != WorkerState.WORKING) {
						level?.setBlock(blockPos, blockState.setValue(
							WorkerState.SEMI_WORKER_STATE,
							WorkerState.WORKING
						), Block.UPDATE_CLIENTS)
					}
				}
			}
		}
	})

	val energyConfig = ConfigurableEnergy(energy)
	var chargeAndroids = true
		set(value) {
			field = value
			markDirtyFast()
		}

	init {
		savetables.stateful(::energy, ENERGY_KEY)
		savetablesConfig.bool(::chargeAndroids)
	}

	private var tickedOnce = false

	override fun tick() {
		super.tick()

		if (!tickedOnce) {
			tickedOnce = true

			if (energy.batteryLevel.isPositive && workerState != WorkerState.WORKING) {
				level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
			} else if (!energy.batteryLevel.isPositive && workerState != WorkerState.IDLE) {
				level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
			}
		}

		if (redstoneControl.isBlockedByRedstone || !chargeAndroids) return
		val level = level ?: return
		val x = blockPos.x.toDouble()
		val y = blockPos.y.toDouble()
		val z = blockPos.z.toDouble()

		for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0)).shuffle(level.otmRandom)) {
			if (ent.matteryPlayer.isAndroid)
				moveEnergy(energy, ent.matteryPlayer.androidEnergy, amount = energy.batteryLevel, simulate = false, ignoreFlowRestrictions = true)
		}
	}
}
