/*
 * Copyright (c) 2026 盐灯水母
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package com.remains_cave.block;

import com.remains_cave.block.entity.TombDoorBlockEntity;
import com.remains_cave.dungeon.room.RoomManager;
import com.remains_cave.item.ModItems;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.*;
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.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
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.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.InteractionHand;
import java.util.ArrayList;
import java.util.List;

public class TombDoorCoreBlock extends Block implements EntityBlock {
    public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
    public static final BooleanProperty OPEN = BlockStateProperties.OPEN;
    public static final BooleanProperty LOCKED = BooleanProperty.create("locked");
    public static final BooleanProperty ONE_WAY = BooleanProperty.create("one_way");
    public static final BooleanProperty COLLISION_ENABLED = BooleanProperty.create("collision_enabled");
    public static final BooleanProperty ROOM_CONTROLLED = BooleanProperty.create("room_controlled"); // 新增：房间控制门

    private static final Logger LOGGER = LoggerFactory.getLogger(TombDoorCoreBlock.class);
    private static final String[] PATTERN = {
            "XCX",
            "XXX",
            "XXX",
            " X "
    };
    private static final int WIDTH = 3;
    private static final int HEIGHT = 4;
    private static final BlockPos CORE_OFFSET = new BlockPos(1, 0, 0);

    public TombDoorCoreBlock() {
        super(Properties.of()
                .mapColor(MapColor.WOOD)
                .strength(20.0F, 20.0F)
                .sound(SoundType.TUFF_BRICKS)
                .requiresCorrectToolForDrops()
                .noOcclusion()
        );
        this.registerDefaultState(this.stateDefinition.any()
                .setValue(FACING, Direction.NORTH)
                .setValue(OPEN, false)
                .setValue(LOCKED, false)
                .setValue(ONE_WAY, false)
                .setValue(COLLISION_ENABLED, true)
                .setValue(ROOM_CONTROLLED, false));
    }

    private boolean canPlaceStructure(LevelReader level, BlockPos corePos, Direction facing) {
        List<BlockPos> partPositions = getPartPositions(corePos, facing);
        for (BlockPos partPos : partPositions) {
            BlockState existingState = level.getBlockState(partPos);
            if (!existingState.isAir()) {
                return false;
            }
        }
        return true;
    }

    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
        builder.add(FACING, OPEN, LOCKED, ONE_WAY, COLLISION_ENABLED, ROOM_CONTROLLED);
    }

    @Nullable
    @Override
    public BlockState getStateForPlacement(BlockPlaceContext context) {
        Direction facing = context.getHorizontalDirection().getOpposite();
        BlockPos corePos = context.getClickedPos();
        if (!canPlaceStructure(context.getLevel(), corePos, facing)) {
            return null;
        }
        // 潜行放置时为单向门
        boolean oneWay = context.getPlayer() != null && context.getPlayer().isShiftKeyDown();
        return this.defaultBlockState()
                .setValue(FACING, facing)
                .setValue(ONE_WAY, oneWay);
    }
    @Override
    protected @NotNull ItemInteractionResult useItemOn(@NotNull ItemStack stack, @NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos,
                                                       Player player, @NotNull InteractionHand hand, @NotNull BlockHitResult hitResult) {
        // 检查是否是创造模式且手持 stately_key
        if (player.isCreative() && stack.is(ModItems.STATELY_KEY.get())) {
            // 如果门已经是房间控制门，则提示并忽略
            if (state.getValue(ROOM_CONTROLLED)) {
                if (!level.isClientSide) {
                    player.displayClientMessage(Component.translatable("door.already_room_controlled"), true);
                }
                return ItemInteractionResult.SUCCESS;
            }

            // 保留原有的 ONE_WAY 属性
            boolean oneWay = state.getValue(ONE_WAY);
            // 修改方块状态为房间控制门，并保留原有 ONE_WAY 值
            BlockState newState = state.setValue(ROOM_CONTROLLED, true).setValue(ONE_WAY, oneWay);
            level.setBlock(pos, newState, 3);

            // 播放音效
            level.playSound(null, pos, SoundEvents.ANVIL_USE, SoundSource.BLOCKS, 1.0F, 1.0F);

            if (!level.isClientSide) {
                player.displayClientMessage(Component.translatable("door.become_room_controlled"), true);
            }
            return ItemInteractionResult.SUCCESS;
        }

        // 其他情况调用父类方法，父类会进一步调用 useWithoutItem 等
        return super.useItemOn(stack, state, level, pos, player, hand, hitResult);
    }
    @Override
    public void onPlace(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState oldState, boolean isMoving) {
        super.onPlace(state, level, pos, oldState, isMoving);
        if (!level.isClientSide) {
            generateStructure(level, pos, state.getValue(FACING));
        }
    }

    @Override
    public void onRemove(@NotNull BlockState state, Level level, @NotNull BlockPos pos, @NotNull BlockState newState, boolean isMoving) {
        if (!level.isClientSide && !state.is(newState.getBlock())) {
            // 门被破坏，从房间管理器中移除
            if (level.getBlockEntity(pos) instanceof TombDoorBlockEntity doorBE) {
                String roomId = doorBE.getRoomId();
                if (roomId != null && !roomId.isEmpty()) {
                    RoomManager.get(level).unregisterDoor(roomId, pos);
                }
            }
            destroyStructure(level, pos, state.getValue(FACING));
        }
        super.onRemove(state, level, pos, newState, isMoving);
    }

    private void generateStructure(Level level, BlockPos corePos, Direction facing) {
        List<BlockPos> partPositions = getPartPositions(corePos, facing);
        for (BlockPos partPos : partPositions) {
            level.setBlock(partPos, ModBlocks.TOMB_DOOR_PART.get().defaultBlockState()
                    .setValue(TombDoorPartBlock.FACING, facing), 3);
        }
    }

    private void destroyStructure(Level level, BlockPos corePos, Direction facing) {
        List<BlockPos> partPositions = getPartPositions(corePos, facing);
        for (BlockPos partPos : partPositions) {
            if (level.getBlockState(partPos).is(ModBlocks.TOMB_DOOR_PART.get())) {
                level.destroyBlock(partPos, false);
            }
        }
    }

    public static List<BlockPos> getPartPositions(BlockPos corePos, Direction facing) {
        List<BlockPos> offsets = new ArrayList<>();
        BlockPos originOffset = new BlockPos(-CORE_OFFSET.getX(), -CORE_OFFSET.getY(), -CORE_OFFSET.getZ());

        for (int y = 0; y < HEIGHT; y++) {
            String row = PATTERN[y];
            for (int x = 0; x < WIDTH; x++) {
                char ch = row.charAt(x);
                if (ch == 'C' || ch == ' ') continue;
                int localX = x;
                int localY = y;
                int localZ = 0;
                int offsetX = localX + originOffset.getX();
                int offsetY = localY + originOffset.getY();
                int offsetZ = localZ + originOffset.getZ();
                BlockPos rotatedOffset = rotateOffset(new BlockPos(offsetX, offsetY, offsetZ), facing);
                offsets.add(corePos.offset(rotatedOffset));
            }
        }
        return offsets;
    }

    public static BlockPos rotateOffset(BlockPos offset, Direction facing) {
        return switch (facing) {
            case NORTH -> new BlockPos(offset.getX(), offset.getY(), offset.getZ());
            case SOUTH -> new BlockPos(-offset.getX(), offset.getY(), -offset.getZ());
            case WEST -> new BlockPos(offset.getZ(), offset.getY(), -offset.getX());
            case EAST -> new BlockPos(-offset.getZ(), offset.getY(), offset.getX());
            default -> offset;
        };
    }

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

    @Override
    public @NotNull InteractionResult useWithoutItem(@NotNull BlockState state, Level level, @NotNull BlockPos pos,
                                                     @NotNull Player player, @NotNull BlockHitResult hitResult) {
        if (level.getBlockEntity(pos) instanceof TombDoorBlockEntity door) {
            return door.onUse(state, player, hitResult);
        }
        return InteractionResult.PASS;
    }

    @Nullable
    @Override
    public <T extends BlockEntity> BlockEntityTicker<T> getTicker(@NotNull Level level, @NotNull BlockState state, @NotNull BlockEntityType<T> type) {
        if (type == ModBlocks.TOMB_DOOR_BLOCK_ENTITY.get()) {
            return (lvl, pos, st, be) -> TombDoorBlockEntity.tick(lvl, pos, st, (TombDoorBlockEntity) be);
        }
        return null;
    }

    // 门板形状
    private static VoxelShape getDoorShape(Direction facing) {
        double minX = 0.0, maxX = 16.0, minY = 0.0, maxY = 16.0, minZ = 4.0, maxZ = 12.0;
        return switch (facing) {
            case NORTH -> Shapes.box(minX / 16, minY / 16, minZ / 16, maxX / 16, maxY / 16, maxZ / 16);
            case SOUTH -> Shapes.box(minX / 16, minY / 16, 1 - maxZ / 16, maxX / 16, maxY / 16, 1 - minZ / 16);
            case WEST -> Shapes.box(minZ / 16, minY / 16, minX / 16, maxZ / 16, maxY / 16, maxX / 16);
            case EAST -> Shapes.box(1 - maxZ / 16, minY / 16, minX / 16, 1 - minZ / 16, maxY / 16, maxX / 16);
            default -> Shapes.block();
        };
    }

    @Override
    public @NotNull VoxelShape getShape(BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) {
        return getDoorShape(state.getValue(FACING));
    }

    @Override
    public @NotNull VoxelShape getCollisionShape(BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) {
        if (!state.getValue(COLLISION_ENABLED)) {
            return Shapes.empty();
        }
        return getDoorShape(state.getValue(FACING));
    }

    @Override
    public @NotNull RenderShape getRenderShape(@NotNull BlockState state) {
        return RenderShape.INVISIBLE;
    }
}