package com.tiedup.remake.blocks;

import com.tiedup.remake.blocks.entity.MarkerBlockEntity;
import com.tiedup.remake.blocks.entity.ModBlockEntities;
import com.tiedup.remake.cells.MarkerType;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityKidnapper;
import com.tiedup.remake.items.ItemAdminWand;
import java.util.List;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.MapColor;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;

/**
 * Marker Block - Invisible block used to define cell spawn points.
 *
 * Phase: Kidnapper Revamp - Cell System
 *
 * Features:
 * - Invisible (no render)
 * - No collision
 * - Stores cell UUID via BlockEntity
 * - Destroying removes the cell from registry
 *
 * Placed by structure generation or Admin Wand.
 */
public class BlockMarker extends BaseEntityBlock {

    // Small shape for selection/picking
    private static final VoxelShape SHAPE = Block.box(6, 6, 6, 10, 10, 10);

    public BlockMarker() {
        super(
            BlockBehaviour.Properties.of()
                .mapColor(MapColor.NONE)
                .strength(0.5f) // Easy to break
                .sound(SoundType.WOOD)
                .noCollission()
                .noOcclusion()
                .pushReaction(PushReaction.DESTROY)
        );
    }

    // ==================== SHAPE ====================

    @Override
    public VoxelShape getShape(
        BlockState state,
        BlockGetter level,
        BlockPos pos,
        CollisionContext context
    ) {
        // Small hitbox for selection
        return SHAPE;
    }

    @Override
    public VoxelShape getCollisionShape(
        BlockState state,
        BlockGetter level,
        BlockPos pos,
        CollisionContext context
    ) {
        // No collision
        return Shapes.empty();
    }

    @Override
    public VoxelShape getVisualShape(
        BlockState state,
        BlockGetter level,
        BlockPos pos,
        CollisionContext context
    ) {
        // No visual shape
        return Shapes.empty();
    }

    // ==================== RENDER ====================

    @Override
    public RenderShape getRenderShape(BlockState state) {
        // Invisible - no model rendering
        return RenderShape.INVISIBLE;
    }

    @Override
    public float getShadeBrightness(
        BlockState state,
        BlockGetter level,
        BlockPos pos
    ) {
        // Full brightness (no shadow)
        return 1.0f;
    }

    @Override
    public boolean propagatesSkylightDown(
        BlockState state,
        BlockGetter level,
        BlockPos pos
    ) {
        return true;
    }

    // ==================== PARTICLE FEEDBACK ====================

    /**
     * Spawn particles to make the marker visible when a player is holding a wand.
     * This provides visual feedback for the otherwise invisible block.
     */
    @Override
    public void animateTick(
        BlockState state,
        Level level,
        BlockPos pos,
        RandomSource random
    ) {
        // Only show particles if a nearby player is holding an AdminWand
        Player nearestPlayer = level.getNearestPlayer(
            pos.getX() + 0.5,
            pos.getY() + 0.5,
            pos.getZ() + 0.5,
            16.0, // Detection range
            false // Include spectators
        );

        if (nearestPlayer == null) return;

        // Check if player is holding an Admin Wand
        boolean holdingWand =
            nearestPlayer.getMainHandItem().getItem() instanceof
                ItemAdminWand ||
            nearestPlayer.getOffhandItem().getItem() instanceof ItemAdminWand;

        if (!holdingWand) return;

        // Spawn subtle particles at the marker position
        // Use END_ROD for a glowing effect
        if (random.nextInt(3) == 0) {
            // 1 in 3 chance per tick for subtle effect
            level.addParticle(
                ParticleTypes.END_ROD,
                pos.getX() + 0.5 + (random.nextDouble() - 0.5) * 0.3,
                pos.getY() + 0.5 + (random.nextDouble() - 0.5) * 0.3,
                pos.getZ() + 0.5 + (random.nextDouble() - 0.5) * 0.3,
                0,
                0.02,
                0 // Slight upward drift
            );
        }
    }

    // ==================== BLOCK ENTITY ====================

    @Nullable
    @Override
    public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
        return new MarkerBlockEntity(pos, state);
    }

    // ==================== DESTRUCTION ====================

    @Override
    public void onRemove(
        BlockState state,
        Level level,
        BlockPos pos,
        BlockState newState,
        boolean movedByPiston
    ) {
        if (!state.is(newState.getBlock())) {
            // Block is being destroyed, remove the cell from registry
            if (level instanceof ServerLevel serverLevel) {
                BlockEntity be = level.getBlockEntity(pos);
                if (be instanceof MarkerBlockEntity marker) {
                    // Alert kidnappers if this was a WALL marker (potential breach)
                    if (marker.getMarkerType() == MarkerType.WALL) {
                        alertNearbyKidnappersOfBreach(
                            serverLevel,
                            pos,
                            marker.getCellId()
                        );
                    }
                    marker.deleteCell();
                }
            }
        }
        super.onRemove(state, level, pos, newState, movedByPiston);
    }

    /**
     * Alert nearby kidnappers when a WALL marker is destroyed.
     * This indicates a potential breach in the cell that prisoners could escape through.
     *
     * @param level The server level
     * @param breachPos The position of the destroyed wall
     * @param cellId The cell UUID (may be null)
     */
    private void alertNearbyKidnappersOfBreach(
        ServerLevel level,
        BlockPos breachPos,
        UUID cellId
    ) {
        if (cellId == null) {
            return;
        }

        // Find kidnappers within 50 blocks
        AABB searchBox = new AABB(breachPos).inflate(50, 20, 50);
        List<EntityKidnapper> kidnappers = level.getEntitiesOfClass(
            EntityKidnapper.class,
            searchBox
        );

        if (!kidnappers.isEmpty()) {
            TiedUpMod.LOGGER.info(
                "[BlockMarker] WALL destroyed at {}, alerting {} kidnappers",
                breachPos.toShortString(),
                kidnappers.size()
            );

            for (EntityKidnapper kidnapper : kidnappers) {
                kidnapper.onCellBreach(breachPos, cellId);
            }
        }
    }
}
