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

import com.remains_cave.block.TombDoorCoreBlock;
import com.remains_cave.block.ModBlocks;
import com.remains_cave.dungeon.room.RoomManager; // 需要导入
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
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.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.bernie.geckolib.animatable.GeoBlockEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.*;
import software.bernie.geckolib.util.GeckoLibUtil;

public class TombDoorBlockEntity extends BlockEntity implements GeoBlockEntity {
    private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
    private boolean isOpen = false;
    private int openTimer = 0;
    private int closeTimer = 0;
    private String roomId = ""; // 新增：房间ID
    private static final Logger LOGGER = LoggerFactory.getLogger(TombDoorBlockEntity.class);
    private static final int OPEN_ANIM_DURATION_TICKS = 40;
    private static final int CLOSE_ANIM_DURATION_TICKS = 15;
    private boolean clientAnimationSet = false;

    // 碰撞箱切换时机
    private static final int OPEN_COLLISION_DISABLE_TICK = 20;
    private static final int CLOSE_COLLISION_ENABLE_TICK = 8;

    public String getRoomId() { return roomId; }
    // 音效播放时机
    private static final int[] OPEN_GRINDSTONE_TICKS = {40, 30, 24, 18, 13, 8};
    private static final int[] CLOSE_GRINDSTONE_TICKS = {15, 8};
    private static final int OPEN_VAULT_TICK = 38;

    private AnimationController<TombDoorBlockEntity> controller;

    public TombDoorBlockEntity(BlockPos pos, BlockState state) {
        super(ModBlocks.TOMB_DOOR_BLOCK_ENTITY.get(), pos, state);
        this.isOpen = state.getValue(TombDoorCoreBlock.OPEN);
    }

    public static void tick(Level level, BlockPos pos, BlockState state, TombDoorBlockEntity door) {
        if (level.isClientSide) {
            if (!door.clientAnimationSet && door.controller != null) {
                door.setAnimationBasedOnState();
                door.clientAnimationSet = true;
            }
            return;
        }

        boolean playGrindstone = false;
        boolean playVault = false;

        if (door.openTimer > 0) {
            for (int tick : OPEN_GRINDSTONE_TICKS) {
                if (door.openTimer == tick) {
                    playGrindstone = true;
                    break;
                }
            }
            if (door.openTimer == OPEN_VAULT_TICK) playVault = true;

            if (door.openTimer == OPEN_COLLISION_DISABLE_TICK) {
                BlockState coreState = level.getBlockState(pos);
                if (coreState.getBlock() instanceof TombDoorCoreBlock) {
                    level.setBlock(pos, coreState.setValue(TombDoorCoreBlock.COLLISION_ENABLED, false), 3);
                }
            }
            door.openTimer--;
            if (door.openTimer == 0) {
                level.playSound(null, pos, SoundEvents.VAULT_PLACE, SoundSource.BLOCKS, 1.0F, 1.0F);
                BlockState currentState = level.getBlockState(pos);
                if (currentState.getValue(TombDoorCoreBlock.ONE_WAY)) {
                    BlockState newState = currentState.setValue(TombDoorCoreBlock.ONE_WAY, false);
                    level.setBlock(pos, newState, 3);
                }
            }
        }

        if (door.closeTimer > 0) {
            for (int tick : CLOSE_GRINDSTONE_TICKS) {
                if (door.closeTimer == tick) {
                    playGrindstone = true;
                    break;
                }
            }
            if (door.closeTimer == CLOSE_COLLISION_ENABLE_TICK) {
                BlockState coreState = level.getBlockState(pos);
                if (coreState.getBlock() instanceof TombDoorCoreBlock) {
                    level.setBlock(pos, coreState.setValue(TombDoorCoreBlock.COLLISION_ENABLED, true), 3);
                }
            }
            door.closeTimer--;
            if (door.closeTimer == 0) {
                level.playSound(null, pos, SoundEvents.VAULT_PLACE, SoundSource.BLOCKS, 1.0F, 1.0F);
            }
        }

        if (playGrindstone) {
            level.playSound(null, pos, SoundEvents.GRINDSTONE_USE, SoundSource.BLOCKS, 1.0F, 1.0F);
        }
        if (playVault) {
            level.playSound(null, pos, SoundEvents.VAULT_INSERT_ITEM_FAIL, SoundSource.BLOCKS, 1.0F, 1.0F);
        }
    }

    public void setOpen(boolean open) {
        if (this.isOpen == open) return;
        this.isOpen = open;
        if (level != null && !level.isClientSide) {
            BlockState state = getBlockState();
            BlockState newState = state.setValue(TombDoorCoreBlock.OPEN, open);
            if (open) {
                openTimer = OPEN_ANIM_DURATION_TICKS;
                closeTimer = 0;
                triggerAnim("door_controller", "open");
                newState = newState.setValue(TombDoorCoreBlock.COLLISION_ENABLED, true);
            } else {
                closeTimer = CLOSE_ANIM_DURATION_TICKS;
                openTimer = 0;
                triggerAnim("door_controller", "close");
                newState = newState.setValue(TombDoorCoreBlock.COLLISION_ENABLED, false);
            }
            level.setBlock(worldPosition, newState, 3);
        }
    }

    public InteractionResult onUse(BlockState state, Player player, BlockHitResult hitResult) {
        // 动画播放期间禁止交互
        if (openTimer > 0 || closeTimer > 0) {
            // 不显示提示，仅禁止操作
            return InteractionResult.CONSUME;
        }

        // 如果门被锁定，禁止交互
        if (state.getValue(TombDoorCoreBlock.LOCKED)) {
            if (level != null && !level.isClientSide) {
                player.displayClientMessage(Component.translatable("door.locked"), true);
            }
            return InteractionResult.CONSUME;
        }

        boolean isOneWay = state.getValue(TombDoorCoreBlock.ONE_WAY);
        Direction facing = state.getValue(TombDoorCoreBlock.FACING);
        boolean isFront = hitResult.getDirection() == facing;

        if (isOneWay && !isFront) {
            if (!level.isClientSide) {
                player.displayClientMessage(Component.translatable("door.cannot_open_from_this_side"), true);
            }
            return InteractionResult.CONSUME;
        }

        boolean newOpen = !state.getValue(TombDoorCoreBlock.OPEN);
        this.setOpen(newOpen);
        return InteractionResult.SUCCESS;
    }

    @Override
    public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
        controller = new AnimationController<>(this, "door_controller", 0, state -> PlayState.CONTINUE);
        controller.triggerableAnim("open", RawAnimation.begin().thenPlay("open_door").thenLoop("is_open"));
        controller.triggerableAnim("close", RawAnimation.begin().thenPlay("close_door").thenLoop("closed"));
        controllers.add(controller);
    }

    @Override
    protected void loadAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.loadAdditional(tag, registries);
        isOpen = tag.getBoolean("IsOpen");
        openTimer = tag.getInt("OpenTimer");
        closeTimer = tag.getInt("CloseTimer");
        roomId = tag.getString("RoomId");

        // 服务端加载时注册到房间管理器
        if (level != null && !level.isClientSide && !roomId.isEmpty()) {
            RoomManager.get(level).registerDoor(roomId, worldPosition);
        }
    }

    @Override
    public void onLoad() {
        super.onLoad();
        // 服务端：修正碰撞箱状态
        if (level != null && !level.isClientSide) {
            BlockState state = getBlockState();
            if (state.getBlock() instanceof TombDoorCoreBlock) {
                boolean correctCollision = !isOpen;
                if (state.getValue(TombDoorCoreBlock.COLLISION_ENABLED) != correctCollision) {
                    level.setBlock(worldPosition, state.setValue(TombDoorCoreBlock.COLLISION_ENABLED, correctCollision), 3);
                }
            }
        }
    }

//    @Override
//    public void setRemoved() {
//        super.setRemoved();
//        if (level != null && !level.isClientSide && !roomId.isEmpty()) {
//            RoomManager.get(level).unregisterDoor(roomId, worldPosition);
//        }
//    }

    @Override
    public AnimatableInstanceCache getAnimatableInstanceCache() {
        return cache;
    }

    @Override
    protected void saveAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.saveAdditional(tag, registries);
        tag.putBoolean("IsOpen", isOpen);
        tag.putInt("OpenTimer", openTimer);
        tag.putInt("CloseTimer", closeTimer);
        tag.putString("RoomId", roomId);
    }

    @Override
    public @NotNull CompoundTag getUpdateTag(HolderLookup.@NotNull Provider registries) {
        CompoundTag tag = super.getUpdateTag(registries);
        tag.putBoolean("IsOpen", isOpen);
        tag.putInt("OpenTimer", openTimer);
        tag.putInt("CloseTimer", closeTimer);
        tag.putString("RoomId", roomId);
        return tag;
    }

    @Override
    public void handleUpdateTag(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.handleUpdateTag(tag, registries);
        boolean newIsOpen = tag.getBoolean("IsOpen");
        int newOpenTimer = tag.getInt("OpenTimer");
        int newCloseTimer = tag.getInt("CloseTimer");
        boolean animPlaying = newOpenTimer > 0 || newCloseTimer > 0;

        isOpen = newIsOpen;
        openTimer = newOpenTimer;
        closeTimer = newCloseTimer;
        roomId = tag.getString("RoomId");

        if (level != null && level.isClientSide && controller != null && !animPlaying) {
            setAnimationBasedOnState();
        }
    }

    private void setAnimationBasedOnState() {
        if (isOpen) {
            controller.setAnimation(RawAnimation.begin().thenLoop("is_open"));
        } else {
            controller.setAnimation(RawAnimation.begin().thenLoop("closed"));
        }
    }
}