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

import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.MobSpawnType
import net.minecraft.world.entity.SpawnGroupData
import net.minecraft.world.entity.monster.Phantom
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.NaturalSpawner
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import net.minecraftforge.common.ForgeHooks
import net.minecraftforge.event.ForgeEventFactory
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.getShapeForEachState
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.math.facingOne
import ru.dbotthepony.mc.otm.core.math.minus
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.math.rotationOne
import ru.dbotthepony.mc.otm.once
import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.shapes.BlockShapes

class PhantomAttractorBlock : RotatableMatteryBlock(Properties.of().mapColor(MapColor.COLOR_BLUE).sound(SoundType.METAL).destroyTime(3f).explosionResistance(12f).randomTicks()) {
	@Suppress("OVERRIDE_DEPRECATION")
	override fun randomTick(
		blockState: BlockState,
		level: ServerLevel,
		blockPos: BlockPos,
		randomSource: RandomSource
	) {
		if (level.server.isSpawningMonsters && (!level.dimensionType().hasSkyLight || level.skyDarken >= 5 && level.canSeeSky(blockPos.above())) && randomSource.nextDouble() <= 0.4) {
			if (level.getEntitiesOfClass(Phantom::class.java, AABB(
				blockPos - BlockPos(20, 20, 20),
				blockPos + BlockPos(20, 20, 20),
			)).size > 4) {
				return
			}

			var groupData: SpawnGroupData? = null

			for (i in 0 .. randomSource.nextInt(2, 6)) {
				val spawnPos = blockPos + BlockPos(randomSource.nextInt(-11, 11), 20 + randomSource.nextInt(-8, 20), randomSource.nextInt(-11, 11))

				if (
					(!level.dimensionType().hasSkyLight || level.canSeeSky(spawnPos)) &&
					NaturalSpawner.isValidEmptySpawnBlock(level, spawnPos, level.getBlockState(spawnPos), level.getFluidState(blockPos), EntityType.PHANTOM)
				) {
					val phantom = EntityType.PHANTOM.create(level) ?: continue
					phantom.moveTo(spawnPos, 0.0f, 0.0f)
					groupData = ForgeEventFactory.onFinalizeSpawn(phantom, level, level.getCurrentDifficultyAt(spawnPos), MobSpawnType.SPAWNER, groupData, null)
					level.addFreshEntityWithPassengers(phantom)
				}
			}
		}
	}

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

	override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
		if (context.clickedPos.y < context.level.maxBuildHeight - 1 && context.level.getBlockState(context.clickedPos.above()).canBeReplaced(context)) {
			return defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER)
		} else {
			return null
		}
	}

	private val shapes = getShapeForEachState(listOf(rotationProperty, BlockStateProperties.DOUBLE_BLOCK_HALF)) {
		val shape = when (it[BlockStateProperties.DOUBLE_BLOCK_HALF]!!) {
			DoubleBlockHalf.UPPER -> BlockShapes.PHANTOM_ATTRACTOR_TOP.moveY(-1.0)
			DoubleBlockHalf.LOWER -> BlockShapes.PHANTOM_ATTRACTOR_BOTTOM
		}

		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_]!!
	}

	override fun setPlacedBy(
		level: Level,
		blockPos: BlockPos,
		blockState: BlockState,
		entity: LivingEntity?,
		itemStack: ItemStack
	) {
		super.setPlacedBy(level, blockPos, blockState, entity, itemStack)
		level.setBlockAndUpdate(blockPos.above(), defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER))
	}

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

		level.once {
			if (state[BlockStateProperties.DOUBLE_BLOCK_HALF] == DoubleBlockHalf.LOWER) {
				if (!level.getBlockState(pos.above()).`is`(MBlocks.PHANTOM_ATTRACTOR)) {
					dropResources(state, level, pos)
					level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState())
				}
			} else {
				if (!level.getBlockState(pos.below()).`is`(MBlocks.PHANTOM_ATTRACTOR)) {
					level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState())
				}
			}
		}
	}
}
