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

import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
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.state.BlockState
import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.block.entity.AbstractRedstoneControl
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.ProxiedEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities

class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_CHARGER, blockPos, blockState) {
	override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
		return AndroidChargerMenu(containerID, inventory, this)
	}

	val energyConfig = ConfigurableEnergy(ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.ANDROID_CHARGER)), modesTop = FlowDirection.NONE)

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

	override fun tick() {
		super.tick()

		val level = level ?: return
		var available = energyConfig.energy.extractEnergy(energyConfig.energy.batteryLevel, true)
		if (!available.isPositive) return

		val ents = level.getEntitiesInEllipsoid(blockPos.center, Vec3(MachinesConfig.AndroidCharger.RADIUS_WIDTH, MachinesConfig.AndroidCharger.RADIUS_HEIGHT, MachinesConfig.AndroidCharger.RADIUS_WIDTH)) { it is Player }

		ents.sort()

		for ((ent) in ents) {
			val ply = ent.matteryPlayer ?: continue

			if (ply.isAndroid) {
				val received = ply.androidEnergy.receiveEnergyChecked(available, false)
				available -= received
				energyConfig.energy.extractEnergy(received, false)
				if (!available.isPositive) return
			}
		}
	}
}

class AndroidChargerMiddleBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_CHARGER_MIDDLE, blockPos, blockState) {
	override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
		if (proxy.parent == null || lastTileEntity == null) return null
		return AndroidChargerMenu(containerID, inventory, this)
	}

	private val proxy = ProxiedEnergyStorage<ProfiledEnergyStorage<*>>()
	var lastTileEntity: AndroidChargerBlockEntity? = null
		private set
	val energyConfig = ConfigurableEnergy(
		proxy,
		modesBottom = FlowDirection.NONE,
		modesTop = FlowDirection.NONE,
		modesBack = FlowDirection.INPUT,
		modesFront = FlowDirection.INPUT,
		modesLeft = FlowDirection.INPUT,
		modesRight = FlowDirection.INPUT,
	)

	override val redstoneControl = object : AbstractRedstoneControl() {
		override var redstoneSetting: RedstoneSetting
			get() = lastTileEntity?.redstoneControl?.redstoneSetting ?: RedstoneSetting.IGNORED
			set(value) {}
		override var redstoneSignal: Int
			get() = lastTileEntity?.redstoneControl?.redstoneSignal ?: 0
			set(value) {}
	}

	override fun getDisplayName(): Component {
		return lastTileEntity?.getDisplayName() ?: super.getDisplayName()
	}

	override fun tick() {
		super.tick()

		if (proxy.parent == null || lastTileEntity?.isRemoved == true) {
			lastTileEntity = level?.getBlockEntity(blockPos.below()) as? AndroidChargerBlockEntity
			val energy = lastTileEntity?.energyConfig?.energy

			if (proxy.parent !== energy) {
				proxy.parent = energy
				energyConfig.invalidate(true)
			}
		}
	}
}

class AndroidChargerTopBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_CHARGER_TOP, blockPos, blockState) {
	override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
		if (proxy.parent == null || lastTileEntity == null) return null
		return AndroidChargerMenu(containerID, inventory, this)
	}

	private val proxy = ProxiedEnergyStorage<ProfiledEnergyStorage<*>>()
	var lastTileEntity: AndroidChargerBlockEntity? = null
		private set
	val energyConfig = ConfigurableEnergy(
		proxy,
		modesBottom = FlowDirection.NONE,
		modesTop = FlowDirection.INPUT,
		modesBack = FlowDirection.INPUT,
		modesFront = FlowDirection.INPUT,
		modesLeft = FlowDirection.INPUT,
		modesRight = FlowDirection.INPUT,
	)

	override val redstoneControl = object : AbstractRedstoneControl() {
		override var redstoneSetting: RedstoneSetting
			get() = lastTileEntity?.redstoneControl?.redstoneSetting ?: RedstoneSetting.IGNORED
			set(value) {}
		override var redstoneSignal: Int
			get() = lastTileEntity?.redstoneControl?.redstoneSignal ?: 0
			set(value) {}
	}

	override fun getDisplayName(): Component {
		return lastTileEntity?.getDisplayName() ?: super.getDisplayName()
	}

	override fun tick() {
		super.tick()

		if (proxy.parent == null || lastTileEntity?.isRemoved == true) {
			lastTileEntity = level?.getBlockEntity(blockPos.below(2)) as? AndroidChargerBlockEntity
			val energy = lastTileEntity?.energyConfig?.energy

			if (proxy.parent !== energy) {
				proxy.parent = energy
				energyConfig.invalidate(true)
			}
		}
	}
}
