/*
 * 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.ModBlocks;
import com.remains_cave.block.SkeletonKingRemainsBlock;
import com.remains_cave.dungeon.room.RoomManager;
import com.remains_cave.entity.ModEntities;
import com.remains_cave.entity.SkeletonKingEntity;
import com.remains_cave.item.ModItems;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import software.bernie.geckolib.animatable.GeoBlockEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.animation.AnimationController;
import software.bernie.geckolib.animation.PlayState;
import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.animation.Animation;
import software.bernie.geckolib.util.GeckoLibUtil;
import org.jetbrains.annotations.NotNull;

public class SkeletonKingRemainsBlockEntity extends BlockEntity implements GeoBlockEntity {
    private static final RawAnimation STATIC_ANIM = RawAnimation.begin().thenLoop("remains");
    private static final RawAnimation REVIVE2_ANIM = RawAnimation.begin()
            .then("revive2", Animation.LoopType.PLAY_ONCE);

    private boolean reviving = false;
    private int reviveTimer = 0;
    private boolean animationTriggered = false;

    private String roomId = "";
    public void setRoomId(String roomId) { this.roomId = roomId; }
    public String getRoomId() { return roomId; }

    private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);

    public SkeletonKingRemainsBlockEntity(BlockPos pos, BlockState state) {
        super(ModBlocks.SKELETON_KING_REMAINS_BLOCK_ENTITY.get(), pos, state);
    }

    // ========== 服务端逻辑 ==========
    public void serverTick() {
        if (level == null || level.isClientSide) return;

        if (reviving) {
            if (reviveTimer > 0) {
                reviveTimer--;
                if (reviveTimer == 0) {
                    summonKing();
                }
            }
        }
    }

    private void summonKing() {
        if (level == null || level.isClientSide) return;
        Direction facing = getBlockState().getValue(SkeletonKingRemainsBlock.FACING);
        SkeletonKingEntity king = new SkeletonKingEntity(ModEntities.SKELETON_KING.get(), level);
        king.setPos(worldPosition.getX() + 0.5, worldPosition.getY(), worldPosition.getZ() + 0.5);
        king.setYRot(facing.toYRot());
        king.yHeadRot = king.getYRot();
        king.setRemainsInfo(worldPosition, facing);
        king.setIsFromRemains(true);
        level.addFreshEntity(king);
        level.setBlock(worldPosition, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
        if (!roomId.isEmpty()) {
            king.setRoomId(roomId);
            if (level instanceof ServerLevel serverLevel) {
                RoomManager.get(level).activateBoss(roomId, serverLevel);
            }
        }
    }

    public boolean use(Player player, ItemStack stack) {
        if (level == null || level.isClientSide) return false;
        if (!reviving && stack.getItem() == ModItems.CRIMSON_CRYSTAL.get()) {
            if (!player.getAbilities().instabuild) {
                stack.shrink(1);
            }
            reviving = true;
            reviveTimer = 40;
            syncToClient();
            level.playSound(null, worldPosition, SoundEvents.AMBIENT_CAVE.value(), SoundSource.BLOCKS, 1.0F, 1.0F);
            return true;
        }
        return false;
    }

    private void syncToClient() {
        if (level != null && !level.isClientSide) {
            setChanged();
            level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), Block.UPDATE_ALL);
            if (level instanceof ServerLevel serverLevel) {
                serverLevel.getChunkSource().blockChanged(worldPosition);
                var packet = ClientboundBlockEntityDataPacket.create(this);
                serverLevel.getChunkSource().chunkMap.getPlayers(new ChunkPos(worldPosition), false)
                        .forEach(player -> player.connection.send(packet));
            }
        }
    }

    // ========== 客户端逻辑 ==========
    public void clientTick() {
        if (level == null || !level.isClientSide) return;
        if (reviving && !animationTriggered) {
            this.triggerAnim("remains_controller", "revive2");
            animationTriggered = true;
        }
    }

    // ========== GeckoLib 动画注册 ==========
    @Override
    public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
        controllers.add(new AnimationController<>(this, "remains_controller", 0, state -> {
            if (reviving) {
                return PlayState.CONTINUE;
            }
            return state.setAndContinue(STATIC_ANIM);
        }).triggerableAnim("revive2", REVIVE2_ANIM));
    }

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

    // ========== 数据同步 ==========
    @Override
    protected void saveAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.saveAdditional(tag, registries);
        tag.putBoolean("Reviving", reviving);
        tag.putInt("ReviveTimer", reviveTimer);
        tag.putString("RoomId", roomId);
    }

    @Override
    protected void loadAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.loadAdditional(tag, registries);
        reviving = tag.getBoolean("Reviving");
        reviveTimer = tag.getInt("ReviveTimer");
        roomId = tag.getString("RoomId");
    }

    @Override
    public @NotNull CompoundTag getUpdateTag(HolderLookup.@NotNull Provider registries) {
        CompoundTag tag = super.getUpdateTag(registries);
        tag.putBoolean("Reviving", reviving);
        tag.putInt("ReviveTimer", reviveTimer);
        return tag;
    }

    @Override
    public void handleUpdateTag(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.handleUpdateTag(tag, registries);
        reviving = tag.getBoolean("Reviving");
        reviveTimer = tag.getInt("ReviveTimer");
        if (level != null && level.isClientSide && reviving && !animationTriggered) {
            net.minecraft.client.Minecraft.getInstance().execute(() -> {
                this.triggerAnim("remains_controller", "revive2");
            });
            animationTriggered = true;
        }
    }
}