/*
 *  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.blockentity;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
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 org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.eroticdungeongame.api.EroticDungeonGameApi;
import top.r3944realms.eroticdungeongame.content.block.AbstractSeatBlock;
import top.r3944realms.eroticdungeongame.content.entity.SeatEntity;
import top.r3944realms.eroticdungeongame.content.util.FurnitureHelper;
import top.r3944realms.eroticdungeongame.core.device.ISeatType;
import top.r3944realms.eroticdungeongame.core.service.SeatService;
import top.r3944realms.lib39.util.nbt.NBTReader;
import top.r3944realms.lib39.util.nbt.NBTWriter;

import java.util.Objects;
import java.util.UUID;

/**
 * 地牢座椅方块实体 - 处理玩家坐在束缚设备上的逻辑
 */
@SuppressWarnings("unused")
public abstract class BaseSeatBlockEntity extends BlockEntity {
    private UUID boundPlayerUUID;
    private long lockCode = -1;
    private final String LOCK_CODE = "lock_code";
    public long getLockCode() {
        return lockCode;
    }
    public boolean hasLockCode() {
        return lockCode != -1;
    }

    public void setLockCode(long lock) {
        this.lockCode = lock;
    }
    public BaseSeatBlockEntity(BlockEntityType<? extends BaseSeatBlockEntity> entity, BlockPos blockPos, BlockState blockState) {
        super(entity, blockPos, blockState);

    }

    public UUID getBoundPlayerUUID() {
        return this.boundPlayerUUID;
    }

    public void setBoundPlayerUUID(UUID uuid) {
        this.boundPlayerUUID = uuid;
        setChanged();
    }


    /**
     * 绑定玩家到座椅
     */
    public boolean bindPlayerToSeat(Level level, BlockPos blockPos, @NotNull BlockState blockState, Player player) {
        ISeatType ISeatType = FurnitureHelper.getSeatType(blockState.getBlock());
        if (ISeatType != null) {
            boolean success = SeatService.bindPlayerToSeat(level, blockPos, player, ISeatType);
            if (success) {
                playAnimation(player, ISeatType);
            }
            return success;
        }
        return false;
    }

    protected final void playAnimation(Player player, ISeatType ISeatType) {
        if(getPlayerAnimationNumber() == 1) {
            SeatService.playBindingAnimation(player, ISeatType);
        } else SeatService.playBindingAnimation(player, ISeatType, getPlayerAnimationNumber());
    }

    public void passengerRot(@NotNull Entity passenger, @NotNull SeatEntity seat) {
        // 固定身体旋转
        passenger.setYBodyRot(seat.getYRot());

        if (passenger instanceof LivingEntity livingEntity) {
            // 获取当前头部旋转
            float currentHeadYaw = livingEntity.getYRot();
            float seatYaw = seat.getYRot();

            // 限制头部旋转范围（例如 ±90度）
            float maxHeadTurn = 45.0f;
            float diff = Mth.wrapDegrees(currentHeadYaw - seatYaw);

            // 应用限制
            if (Math.abs(diff) > maxHeadTurn) {
                if (diff > 0) {
                    livingEntity.setYRot(seatYaw + maxHeadTurn);
                } else {
                    livingEntity.setYRot(seatYaw - maxHeadTurn);
                }
                livingEntity.yHeadRot = livingEntity.getYRot();
            }

            // 保持身体固定
            livingEntity.yBodyRot = seatYaw;
        }
    }

    public int getPlayerAnimationNumber() {
        return 1;
    }

    /**
     * 翻转座椅方向
     */
    public void flipSeatDirection(Level level, BlockPos blockPos, @NotNull BlockState blockState) {
        Direction direction = blockState.getValue(AbstractSeatBlock.FACING);
        boolean isFlipped = blockState.getValue(AbstractSeatBlock.FLIPPED);
        ISeatType furnitureType = FurnitureHelper.getSeatType(blockState.getBlock());
        if (furnitureType == null) {
            return;
        }

        float yaw = calculateSeatYaw(isFlipped ? direction : direction.getOpposite(), furnitureType);
        Player playerByUUID = level.getPlayerByUUID(boundPlayerUUID);
        // 更新实体朝向
        if (playerByUUID != null) {
            playerByUUID.getCapability(EroticDungeonGameApi.PLAYER_DUNGEON_DATA_CAP).ifPresent(cap -> {
                BlockPos deviceMainBlockPos = cap.getDeviceMainBlockPos();
                if (playerByUUID.isPassenger() || deviceMainBlockPos != null) {
                    Entity vehicle = playerByUUID.getVehicle();
                    if (vehicle instanceof SeatEntity seat) {
                        boolean flag = Objects.equals(seat.getLinkedBlockPos(), deviceMainBlockPos);
                        if (flag) {
                            seat.setYRot(yaw);
                            // 翻转方块状态
                            updateBlockState(level, blockPos, blockState, AbstractSeatBlock.FLIPPED, !isFlipped);
                        }
                    }
                }
            });
        }
    }

    /**
     * 计算座椅朝向
     */
    @Contract(pure = true)
    private float calculateSeatYaw(@NotNull Direction direction, ISeatType furnitureType) {
        float yaw = switch (direction) {
            case NORTH -> 0.0f;
            case WEST -> 270.0f;
            case EAST -> 90.0f;
            default -> 180.0f;
        };
        return yaw + (furnitureType.isOppositeDirection() ? -furnitureType.getYawOffset(): furnitureType.getYawOffset());
    }

    /**
     * 更新多方块结构的状态
     */
    private void updateBlockState(Level level, BlockPos blockPos, @NotNull BlockState blockState,
                                  BooleanProperty property, boolean value) {
        ISeatType ISeatType = FurnitureHelper.getSeatType(blockState.getBlock());
        if (ISeatType == null) return;
        FurnitureHelper.setBlockStates(level, property, value, ISeatType.getFurnitureShapeType().getAllPositions(level, blockState, blockPos));
    }

    @Override
    public void saveAdditional(@NotNull CompoundTag compoundTag) {
        super.saveAdditional(compoundTag);
        boolean hasBoundPlayer = this.boundPlayerUUID != null;
        NBTWriter.of(compoundTag)
                        .string("Lock", "3944Realms")
                        .longValue(LOCK_CODE, getLockCode())
                        .uuidValueIf("PlayerUUID", hasBoundPlayer, this::getBoundPlayerUUID);
    }

    @Override
    public void load(@NotNull CompoundTag compoundTag) {
        super.load(compoundTag);
        NBTReader.of(compoundTag)
                .string("Lock",ig -> {})
                .longValue(LOCK_CODE, this::setLockCode)
                .uuid("PlayerUUID", this::setBoundPlayerUUID);
    }

    @Override
    public Packet<ClientGamePacketListener> getUpdatePacket() {
        return ClientboundBlockEntityDataPacket.create(this);
    }

    @Override
    public @NotNull CompoundTag getUpdateTag() {
        return saveWithoutMetadata();
    }
}