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

import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.util.StringRepresentable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.material.PushReaction
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerMiddleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerTopBlockEntity
import ru.dbotthepony.mc.otm.block.getShapeForEachState
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.gracefulBlockBreak
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.oncePre
import ru.dbotthepony.mc.otm.shapes.BlockShapes

class AndroidChargerBlock : RotatableMatteryBlock(Properties.of().destroyTime(2.5f).explosionResistance(40f).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops()), EntityBlock {
	enum class Type : StringRepresentable {
		BASE,
		MIDDLE,
		TOP;

		override fun getSerializedName(): String {
			return name.lowercase()
		}
	}

	override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
		super.createBlockStateDefinition(builder)
		builder.add(PART)
	}

	init {
		registerDefaultState(defaultBlockState().setValue(PART, Type.BASE))
	}

	override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
		val level = context.level
		if (level.isOutsideBuildHeight(context.clickedPos + BlockPos(0, 2, 0))) return null

		for (i in 1 .. 2) {
			val pos = context.clickedPos + BlockPos(0, i, 0)
			if (!level.getBlockState(pos).canBeReplaced(context)) return null
		}

		return super.getStateForPlacement(context)
	}

	override fun setPlacedBy(level: Level, blockPos: BlockPos, blockState: BlockState, entity: LivingEntity?, itemStack: ItemStack) {
		super.setPlacedBy(level, blockPos, blockState, entity, itemStack)

		if (blockState[PART] == Type.BASE) {
			level.setBlock(blockPos.above(), blockState.setValue(PART, Type.MIDDLE), UPDATE_ALL)
			level.setBlock(blockPos.above().above(), blockState.setValue(PART, Type.TOP), UPDATE_ALL)
		}
	}

	override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity? {
		return when (p_153216_[PART]!!) {
			Type.BASE -> AndroidChargerBlockEntity(p_153215_, p_153216_)
			Type.MIDDLE -> AndroidChargerMiddleBlockEntity(p_153215_, p_153216_)
			Type.TOP -> AndroidChargerTopBlockEntity(p_153215_, p_153216_)
		}
	}

	override fun <T : BlockEntity?> getTicker(p_153212_: Level, blockState: BlockState, p_153214_: BlockEntityType<T>): BlockEntityTicker<T>? {
		if (p_153212_.isClientSide) return null

		return when (blockState[PART]!!) {
			Type.BASE -> BlockEntityTicker { _, _, _, t -> if (t is AndroidChargerBlockEntity) t.tick() }
			Type.MIDDLE -> BlockEntityTicker { _, _, _, t -> if (t is AndroidChargerMiddleBlockEntity) t.tick() }
			Type.TOP -> BlockEntityTicker { _, _, _, t -> if (t is AndroidChargerTopBlockEntity) t.tick() }
		}
	}

	override fun getDestroyProgress(p_60466_: BlockState, p_60467_: Player, p_60468_: BlockGetter, p_60469_: BlockPos): Float {
		// запрет на ломание не нижнего блока игроком
		if (p_60466_[PART] != Type.BASE) return 0f
		return super.getDestroyProgress(p_60466_, p_60467_, p_60468_, p_60469_)
	}

	override fun neighborChanged(state: BlockState, level: Level, pos: BlockPos, neighbour: Block, neighbourPos: BlockPos, movedByPiston: Boolean) {
		super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)

		level.oncePre {
			if (level.getBlockState(pos) == state) {
				when (state[PART]!!) {
					Type.BASE -> {
						val a = level.getBlockState(pos.above())
						val b = level.getBlockState(pos.above().above())

						if (a.block != this || b.block != this || a[PART] != Type.MIDDLE || b[PART] != Type.TOP) {
							level.gracefulBlockBreak(pos, state)
						}
					}

					Type.MIDDLE -> {
						val a = level.getBlockState(pos.below())
						val b = level.getBlockState(pos.above())

						if (a.block != this || b.block != this || a[PART] != Type.BASE || b[PART] != Type.TOP) {
							level.setBlock(pos, Blocks.AIR.defaultBlockState(), UPDATE_ALL)
						}
					}

					Type.TOP -> {
						val a = level.getBlockState(pos.below())
						val b = level.getBlockState(pos.below().below())

						if (a.block != this || b.block != this || a[PART] != Type.MIDDLE || b[PART] != Type.BASE) {
							level.setBlock(pos, Blocks.AIR.defaultBlockState(), UPDATE_ALL)
						}
					}
				}
			}
		}
	}

	override fun appendHoverText(p_49816_: ItemStack, p_49817_: BlockGetter?, p_49818_: MutableList<Component>, p_49819_: TooltipFlag) {
		super.appendHoverText(p_49816_, p_49817_, p_49818_, p_49819_)
		WorkerEnergyStorage.appendHoverText(p_49816_, p_49817_, p_49818_, p_49819_)
		MatteryPoweredBlockEntity.appendHoverText(p_49816_, p_49817_, p_49818_, p_49819_)
	}

	private val shapes = getShapeForEachState(listOf(rotationProperty, PART)) {
		val shape = when (it[PART]!!) {
			Type.BASE -> BlockShapes.ANDROID_CHARGER_BASE
			Type.MIDDLE -> BlockShapes.ANDROID_CHARGER_MIDDLE
			Type.TOP -> BlockShapes.ANDROID_CHARGER_TOP
		}

		shape.rotateFromNorth(it[rotationProperty]).computeShape()
	}

	override fun getShape(
		p_60555_: BlockState,
		p_60556_: BlockGetter,
		p_60557_: BlockPos,
		p_60558_: CollisionContext
	): VoxelShape {
		return shapes[p_60555_]!!
	}

	companion object {
		val PART: EnumProperty<Type> = EnumProperty.create("part", Type::class.java)
	}
}
