/*
 *  Copyright 2025-2026 R3944Realms
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package top.r3944realms.eroticdungeongame.content.block;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
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.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.eroticdungeongame.EroticDungeon;
import top.r3944realms.eroticdungeongame.content.block.blockentity.BaseSeatBlockEntity;
import top.r3944realms.eroticdungeongame.content.util.FurnitureHelper;
import top.r3944realms.eroticdungeongame.core.register.EDGItems;
import top.r3944realms.eroticdungeongame.core.service.SeatService;

import javax.annotation.Nullable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 座椅方块接口
 * 定义所有座椅类方块应该实现的基本功能
 */
public interface ISeatBlock extends EntityBlock, IShapeCache<Map<Direction, VoxelShape>> {
    Map<Class<? extends ISeatBlock>, Map<?, Map<Direction, VoxelShape>>> CLASS_CACHE = new ConcurrentHashMap<>();
    DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
    BooleanProperty OCCUPIED = BooleanProperty.create("occupied");
    BooleanProperty FLIPPED = BooleanProperty.create("flipped");
    /**
     * 设置方块的碰撞箱形状
     */
    void setupShape();

    /**
     * 获取形状映射
     * @return 方向到形状的映射
     */
    default Map<Direction, VoxelShape> getShapeMap() {
        return getShapeCacheMap();
    }

    /**
     * 设置形状映射
     * @param shapeMap 方向到形状的映射
     */
    default void setShapeMap(Map<Direction, VoxelShape> shapeMap) {
        setShapeCacheMap(shapeMap);
    }

    /**
     * 处理玩家与座椅的交互
     * @param blockState 方块状态
     * @param level 世界
     * @param blockPos 方块位置
     * @param player 玩家
     * @param hand 交互的手
     * @param hitResult 点击结果
     * @return 交互结果
     */
    default InteractionResult handleSeatInteraction(BlockState blockState, @NotNull Level level, BlockPos blockPos,
                                                    Player player, InteractionHand hand, BlockHitResult hitResult) {
        // 客户端或副手直接返回
        if (level.isClientSide || hand == InteractionHand.OFF_HAND) {
            return InteractionResult.SUCCESS;
        }
        ItemStack itemInHand = player.getItemInHand(hand);
        if (itemInHand.is(EDGItems.DEVICE_KEY.get())) {
            return InteractionResult.PASS;
        }

        BaseSeatBlockEntity deviceEntity = FurnitureHelper.getSeatBlockEntity(level, blockPos);
        if (deviceEntity != null) {
            if (blockState.getValue(OCCUPIED)) {
                // 设备已被占用
                if (isRestraintDevice()) {
                    Player boundPlayer = level.getPlayerByUUID(deviceEntity.getBoundPlayerUUID());
                    if (boundPlayer != null) {
                        return InteractionResult.SUCCESS;
                    } else FurnitureHelper.setSeatOccupied(level, blockPos, false);

                }
            } else {
                // 设备空闲 - 绑定玩家
                if (!player.isShiftKeyDown()) {
                    if (bindPlayerToSeat(level, blockPos, blockState, player)) return InteractionResult.SUCCESS;
                    return InteractionResult.FAIL;
                }
            }
        }
        return InteractionResult.SUCCESS;
    }

    /**
     * 绑定玩家到座椅
     * @param level 世界
     * @param blockPos 方块位置
     * @param blockState 方块状态
     * @param player 玩家
     * @return 是否绑定成功
     */
    default boolean bindPlayerToSeat(Level level, BlockPos blockPos, BlockState blockState, Player player) {
        BaseSeatBlockEntity deviceEntity = FurnitureHelper.getSeatBlockEntity(level, blockPos);
        if (deviceEntity != null) {
            return deviceEntity.bindPlayerToSeat(level, blockPos, blockState, player);
        }
        return false;
    }

    /**
     * 从座椅释放玩家
     * @param level 世界
     * @param blockPos 方块位置
     * @param blockState 方块状态
     * @return 是否释放成功
     */
    default boolean releasePlayerFromSeat(Level level, BlockPos blockPos, BlockState blockState) {
        BaseSeatBlockEntity deviceEntity = FurnitureHelper.getSeatBlockEntity(level, blockPos);
        if (deviceEntity != null && blockState.getValue(OCCUPIED) && deviceEntity.getBoundPlayerUUID() != null) {
            Player boundPlayer = level.getPlayerByUUID(deviceEntity.getBoundPlayerUUID());
            if (boundPlayer != null) {
                return SeatService.releasePlayerFromBlock(level, blockPos);
            }
        }
        return false;
    }

    /**
     * 翻转座椅方向
     * @param level 世界
     * @param blockPos 方块位置
     * @param blockState 方块状态
     */
    default void flipSeatDirection(Level level, BlockPos blockPos, BlockState blockState) {
        BaseSeatBlockEntity deviceEntity = FurnitureHelper.getSeatBlockEntity(level, blockPos);
        if (deviceEntity != null) {
            deviceEntity.flipSeatDirection(level, blockPos, blockState);
        }
    }

    /**
     * 检查座椅是否被占用
     * @param blockState 方块状态
     * @return 是否被占用
     */
    default boolean isOccupied(@NotNull BlockState blockState) {
        return blockState.getValue(OCCUPIED);
    }

    /**
     * 设置座椅占用状态
     * @param blockState 方块状态
     * @param occupied 是否占用
     * @return 更新后的方块状态
     */
    default BlockState setOccupied(@NotNull BlockState blockState, boolean occupied) {
        return blockState.setValue(OCCUPIED, occupied);
    }

    /**
     * 检查座椅是否翻转
     * @param blockState 方块状态
     * @return 是否翻转
     */
    default boolean isFlipped(@NotNull BlockState blockState) {
        return blockState.getValue(FLIPPED);
    }

    /**
     * 获取座椅面向的方向
     * @param blockState 方块状态
     * @return 面向方向
     */
    default Direction getFacing(@NotNull BlockState blockState) {
        return blockState.getValue(FACING);
    }

    /**
     * 获取座椅的红石信号强度
     * @param blockState 方块状态
     * @return 红石信号强度（占用时为15，否则为0）
     */
    default int getSeatRedstoneSignal(BlockState blockState) {
        return isOccupied(blockState) ? 15 : 0;
    }

    /**
     * 检查是否是束缚设备
     * @return 是否是束缚设备
     */
    default boolean isRestraintDevice() {
        try {
            return FurnitureHelper.isRestraintDevice((Block) this);
        } catch (ClassCastException e) {
            EroticDungeon.LOGGER.error("{} is not Block class",this.getClass().getName(), e);
            throw e;
        }
    }

    /**
     * 当座椅被移除时的处理
     * @param blockState 方块状态
     * @param level 世界
     * @param blockPos 方块位置
     * @param newState 新的方块状态
     * @param moved 是否被移动
     */
    default void onSeatRemoved(BlockState blockState, @NotNull Level level, BlockPos blockPos,
                               BlockState newState, boolean moved) {
        if (!level.isClientSide && blockState.getBlock() != newState.getBlock()) {
            if (!releasePlayerFromSeat(level, blockPos, blockState)) {
//                EroticDungeon.getLogger().warn("Failed to release seat from {} to {}", blockPos, blockState);
            }
        }
    }
    @Nullable
    default MenuProvider getMenuProvider(BlockState state, @NotNull Level level, BlockPos pos) {
        BlockEntity blockentity = level.getBlockEntity(pos);
        return blockentity instanceof MenuProvider ? (MenuProvider)blockentity : null;
    }

    @Nullable
    default BlockEntity getBlockEntity(BlockState state, @NotNull Level level, BlockPos pos) {
        BlockEntity blockentity = level.getBlockEntity(pos);
        return blockentity instanceof BlockEntity ? blockentity : null;
    }

    @Nullable
    @SuppressWarnings("unchecked")
    static <E extends BlockEntity, A extends BlockEntity> BlockEntityTicker<A> createTickerHelper(
            BlockEntityType<A> serverType,
            BlockEntityType<E> clientType,
            BlockEntityTicker<? super E> ticker) {
        return clientType == serverType ? (BlockEntityTicker<A>) ticker : null;
    }
}
