package com.tiedup.remake.blocks;

import com.tiedup.remake.blocks.entity.IronBarDoorBlockEntity;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.items.ItemCellKey;
import com.tiedup.remake.items.ItemKey;
import com.tiedup.remake.items.ItemMasterKey;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
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.LevelAccessor;
import net.minecraft.world.level.block.*;
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.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.*;
import net.minecraft.world.level.material.MapColor;
import net.minecraft.world.phys.BlockHitResult;
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;

/**
 * Iron Bar Door - A door made of iron bars that can be locked.
 *
 * Phase: Kidnapper Revamp - Cell System
 *
 * Features:
 * - Lockable with ItemKey (stores key UUID)
 * - Can be unlocked with matching key, ItemCellKey, or ItemMasterKey
 * - When locked, cannot be opened by redstone or by hand
 * - Visually connects to iron bars (like vanilla iron bars)
 * - Uses DoorBlock mechanics for open/close state
 */
public class BlockIronBarDoor extends DoorBlock implements EntityBlock {

    // VoxelShapes for different orientations - centered like iron bars (7-9 = 2 pixels thick)
    protected static final VoxelShape SOUTH_AABB = Block.box(
        0.0,
        0.0,
        7.0,
        16.0,
        16.0,
        9.0
    );
    protected static final VoxelShape NORTH_AABB = Block.box(
        0.0,
        0.0,
        7.0,
        16.0,
        16.0,
        9.0
    );
    protected static final VoxelShape WEST_AABB = Block.box(
        7.0,
        0.0,
        0.0,
        9.0,
        16.0,
        16.0
    );
    protected static final VoxelShape EAST_AABB = Block.box(
        7.0,
        0.0,
        0.0,
        9.0,
        16.0,
        16.0
    );

    public BlockIronBarDoor() {
        super(
            BlockBehaviour.Properties.of()
                .mapColor(MapColor.METAL)
                .strength(5.0f, 45.0f)
                .sound(SoundType.METAL)
                .requiresCorrectToolForDrops()
                .noOcclusion(),
            BlockSetType.IRON
        );
    }

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

    @Override
    public VoxelShape getShape(
        BlockState state,
        BlockGetter level,
        BlockPos pos,
        CollisionContext context
    ) {
        Direction facing = state.getValue(FACING);
        boolean open = state.getValue(OPEN);
        boolean hingeRight = state.getValue(HINGE) == DoorHingeSide.RIGHT;

        Direction effectiveDirection;
        if (open) {
            effectiveDirection = hingeRight
                ? facing.getCounterClockWise()
                : facing.getClockWise();
        } else {
            effectiveDirection = facing;
        }

        return switch (effectiveDirection) {
            case NORTH -> NORTH_AABB;
            case SOUTH -> SOUTH_AABB;
            case WEST -> WEST_AABB;
            case EAST -> EAST_AABB;
            default -> SOUTH_AABB;
        };
    }

    // ==================== INTERACTION ====================

    @Override
    public InteractionResult use(
        BlockState state,
        Level level,
        BlockPos pos,
        Player player,
        InteractionHand hand,
        BlockHitResult hit
    ) {
        // Get the BlockEntity
        BlockEntity be = level.getBlockEntity(
            getBlockEntityPos(state, pos, level)
        );
        if (!(be instanceof IronBarDoorBlockEntity doorEntity)) {
            return InteractionResult.PASS;
        }

        ItemStack heldItem = player.getItemInHand(hand);

        // Handle key interactions
        if (heldItem.getItem() instanceof ItemMasterKey) {
            // Master key can always unlock
            if (doorEntity.isLocked()) {
                if (!level.isClientSide) {
                    doorEntity.setLocked(false);
                    SystemMessageManager.sendToPlayer(
                        player,
                        SystemMessageManager.MessageCategory.INFO,
                        "Door unlocked with master key"
                    );
                }
                return InteractionResult.sidedSuccess(level.isClientSide);
            }
        } else if (heldItem.getItem() instanceof ItemCellKey) {
            // Cell key can unlock any iron bar door
            if (doorEntity.isLocked()) {
                if (!level.isClientSide) {
                    doorEntity.setLocked(false);
                    SystemMessageManager.sendToPlayer(
                        player,
                        SystemMessageManager.MessageCategory.INFO,
                        "Door unlocked with cell key"
                    );
                }
                return InteractionResult.sidedSuccess(level.isClientSide);
            }
        } else if (heldItem.getItem() instanceof ItemKey key) {
            UUID keyUUID = key.getKeyUUID(heldItem);

            if (doorEntity.isLocked()) {
                // Try to unlock
                if (doorEntity.matchesKey(keyUUID)) {
                    if (!level.isClientSide) {
                        doorEntity.setLocked(false);
                        SystemMessageManager.sendToPlayer(
                            player,
                            SystemMessageManager.MessageCategory.INFO,
                            "Door unlocked"
                        );
                    }
                    return InteractionResult.sidedSuccess(level.isClientSide);
                } else {
                    if (!level.isClientSide) {
                        SystemMessageManager.sendToPlayer(
                            player,
                            SystemMessageManager.MessageCategory.ERROR,
                            "This key doesn't fit this lock"
                        );
                    }
                    return InteractionResult.FAIL;
                }
            } else {
                // Lock the door with this key
                if (!level.isClientSide) {
                    doorEntity.setLockedByKeyUUID(keyUUID);
                    SystemMessageManager.sendToPlayer(
                        player,
                        SystemMessageManager.MessageCategory.INFO,
                        "Door locked"
                    );
                }
                return InteractionResult.sidedSuccess(level.isClientSide);
            }
        }

        // If locked and no valid key, deny access
        if (doorEntity.isLocked()) {
            if (!level.isClientSide) {
                SystemMessageManager.sendToPlayer(
                    player,
                    SystemMessageManager.MessageCategory.ERROR,
                    "This door is locked"
                );
            }
            return InteractionResult.FAIL;
        }

        // Iron doors don't open by hand normally, but we allow it if unlocked
        // Toggle the door state
        if (!level.isClientSide) {
            boolean newOpen = !state.getValue(OPEN);
            setOpen(player, level, state, pos, newOpen);
        }
        return InteractionResult.sidedSuccess(level.isClientSide);
    }

    /**
     * Get the BlockEntity position (handles double-height doors).
     */
    private BlockPos getBlockEntityPos(
        BlockState state,
        BlockPos pos,
        Level level
    ) {
        // LOW FIX: Check if HALF property exists before accessing (WorldEdit/SetBlock safety)
        if (!state.hasProperty(HALF)) {
            // Invalid state - assume lower half
            return pos;
        }

        // BlockEntity is always on the lower half
        if (state.getValue(HALF) == DoubleBlockHalf.UPPER) {
            return pos.below();
        }
        return pos;
    }

    // ==================== REDSTONE ====================

    @Override
    public void neighborChanged(
        BlockState state,
        Level level,
        BlockPos pos,
        Block neighborBlock,
        BlockPos neighborPos,
        boolean movedByPiston
    ) {
        // Check if locked before allowing redstone control
        BlockEntity be = level.getBlockEntity(
            getBlockEntityPos(state, pos, level)
        );
        if (
            be instanceof IronBarDoorBlockEntity doorEntity &&
            doorEntity.isLocked()
        ) {
            // Door is locked, ignore redstone
            return;
        }

        // Allow normal redstone behavior if unlocked
        super.neighborChanged(
            state,
            level,
            pos,
            neighborBlock,
            neighborPos,
            movedByPiston
        );
    }

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

    @Nullable
    @Override
    public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
        // Only create block entity for the lower half
        if (state.getValue(HALF) == DoubleBlockHalf.LOWER) {
            return new IronBarDoorBlockEntity(pos, state);
        }
        return null;
    }

    // ==================== PLACEMENT ====================

    @Override
    public void setPlacedBy(
        Level level,
        BlockPos pos,
        BlockState state,
        @Nullable net.minecraft.world.entity.LivingEntity placer,
        ItemStack stack
    ) {
        super.setPlacedBy(level, pos, state, placer, stack);
        // BlockEntity is automatically created for lower half
    }

    @Override
    public void onRemove(
        BlockState state,
        Level level,
        BlockPos pos,
        BlockState newState,
        boolean movedByPiston
    ) {
        if (!state.is(newState.getBlock())) {
            // Block entity is removed automatically
        }
        super.onRemove(state, level, pos, newState, movedByPiston);
    }

    // ==================== VISUAL ====================

    @Override
    public float getShadeBrightness(
        BlockState state,
        BlockGetter level,
        BlockPos pos
    ) {
        // Allow some light through like iron bars
        return 1.0f;
    }

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