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

import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.fluids.FluidType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.core.animation.AnimatableManager;
import software.bernie.geckolib.core.animation.AnimationController;
import software.bernie.geckolib.core.animation.AnimationState;
import software.bernie.geckolib.core.animation.RawAnimation;
import software.bernie.geckolib.core.object.PlayState;
import software.bernie.geckolib.util.GeckoLibUtil;
import top.r3944realms.eroticdungeongame.config.EDGConfig;
import top.r3944realms.eroticdungeongame.core.register.EDGEntities;
import top.r3944realms.eroticdungeongame.core.register.EDGItems;
import top.r3944realms.lib39.util.nbt.NBTReader;
import top.r3944realms.lib39.util.nbt.NBTWriter;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;

public class IronBallEntity extends LivingEntity implements GeoEntity {
    private static final EntityDataAccessor<CompoundTag> DATA_ENCHANT = SynchedEntityData.defineId(IronBallEntity.class, EntityDataSerializers.COMPOUND_TAG);
    private static final EntityDataAccessor<Boolean> DATA_SHOULD_BOUNCE = SynchedEntityData.defineId(IronBallEntity.class, EntityDataSerializers.BOOLEAN);
    private static final EntityDataAccessor<Boolean> DATA_HAS_BOUNCED = SynchedEntityData.defineId(IronBallEntity.class, EntityDataSerializers.BOOLEAN);
    private static final EntityDataAccessor<Boolean> DATA_IS_BOUNCING = SynchedEntityData.defineId(IronBallEntity.class, EntityDataSerializers.BOOLEAN);

    private static final String SHOULD_BOUNCE_KEY = "ShouldBounce";
    private static final String HAS_BOUNCED_KEY = "HasBounced";
    private static final String IS_BOUNCING_KEY = "IsBouncing";

    private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
    public static final RawAnimation BOUNCE_ANIM = RawAnimation.begin().thenPlay("ball.bounce");

    private int fallStartY = -1;
    private int bounceCooldown = 0;
    private static final int BOUNCE_COOLDOWN_TICKS = 20; // 动画播放后的冷却时间

    public IronBallEntity(EntityType<? extends IronBallEntity> entityType, Level level) {
        super(entityType, level);
    }

    public IronBallEntity(Level level, @NotNull BlockPos pos) {
        super(EDGEntities.IRON_BALL.get(), level);
        this.setPos((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D);
    }

    @Contract("_, _, _ -> new")
    public static @NotNull IronBallEntity createFromItem(Level level, ItemStack itemInHand, BlockPos pos) {
        return new IronBallEntity(level, pos);
    }

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.define(DATA_ENCHANT, NBTWriter.builder().build());
        this.entityData.define(DATA_SHOULD_BOUNCE, false);
        this.entityData.define(DATA_HAS_BOUNCED, false);
        this.entityData.define(DATA_IS_BOUNCING, false);
    }

    @Override
    public @NotNull InteractionResult interact(@NotNull Player interact, @Nonnull InteractionHand hand) {
        if (this.level().isClientSide()) {
            return InteractionResult.SUCCESS;
        } else if(hand == InteractionHand.MAIN_HAND) {
            if(!interact.isCrouching() && EDGConfig.SERVER.ANCHORING_ALLOW_ANCHORING_TO_WEIGHTED_ANCHORS.get()) {
                boolean flag = false;
                double maxDist = EDGConfig.SERVER.ANCHORING_MAX_CHAIN_LENGTH.get();
                List<LivingEntity> list = this.level().getEntitiesOfClass(LivingEntity.class,
                        new AABB(this.getX() - maxDist - 2.0D, this.getY() - maxDist - 2.0D, this.getZ() - maxDist - 2.0D,
                                this.getX() + maxDist + 2.0D, this.getY() + maxDist + 2.0D, this.getZ() + maxDist + 2.0D));

                for (LivingEntity entity : list) {
                    IAnchorableEntity anchorableEntity = (IAnchorableEntity) entity;
                    if (anchorableEntity.edg$getAnchor() == interact) {
                        anchorableEntity.edg$setAnchoredTo(this);
                        flag = true;
                    }
                }

                boolean flag1 = false;
                if (!flag) {
                    for (LivingEntity entity : list) {
                        IAnchorableEntity anchorableEntity = (IAnchorableEntity) entity;
                        if (anchorableEntity.edg$isAnchored() && anchorableEntity.edg$getAnchor() == this) {
                            anchorableEntity.edg$setAnchoredTo(null);
                            flag1 = true;
                        }
                    }
                    if(flag1)
                        level().playSound(null, blockPosition(), SoundEvents.CHAIN_BREAK, SoundSource.PLAYERS, 0.7f, 1);
                }

                if(flag)
                    level().playSound(null, blockPosition(), SoundEvents.CHAIN_PLACE, SoundSource.PLAYERS, 0.7f, 1);
                if(flag1)
                    level().playSound(null, blockPosition(), SoundEvents.CHAIN_BREAK, SoundSource.PLAYERS, 0.7f, 1);

                if (flag || flag1) {
                    this.gameEvent(GameEvent.BLOCK_ATTACH, interact);
                }

                return InteractionResult.CONSUME;
            } else {
                ItemStack stack = getDroppedItem();
                ItemEntity entity = new ItemEntity(level(), position().x(), position().y(), position().z(), stack);
                level().addFreshEntity(entity);

                level().playSound(null, blockPosition(), SoundEvents.ANVIL_BREAK, SoundSource.PLAYERS, 0.7f, 1);
                this.discard();
            }
        }

        return InteractionResult.FAIL;
    }

    @Override
    public void tick() {
        super.tick();

        // 更新冷却时间
        if (bounceCooldown > 0) {
            bounceCooldown--;
        }

        // 记录开始掉落的高度（只记录从非地面开始的掉落）
        if (fallStartY == -1 && !this.onGround() && !this.isInWater() && !this.isNoGravity()) {
            fallStartY = (int) this.getY();
        }

        // 检查是否落地并需要播放动画
        if (this.onGround() && !this.isInWater() && bounceCooldown == 0) {
            if (fallStartY != -1) {
                int fallDistance = fallStartY - (int) this.getY();
                int minFallHeight = 3;

                // 如果掉落高度足够且还没有触发弹跳
                if (fallDistance >= minFallHeight && !this.entityData.get(DATA_HAS_BOUNCED)) {
                    this.entityData.set(DATA_SHOULD_BOUNCE, true);
                }
            }

            // 重置掉落记录
            fallStartY = -1;
        }

        // 如果在空中，重置弹跳完成标记（允许下次落地再次弹跳）
        if (!this.onGround() && this.entityData.get(DATA_HAS_BOUNCED)) {
            this.entityData.set(DATA_HAS_BOUNCED, false);
        }

        // 动画播放完成后重置 SHOULD_BOUNCE
        if (this.entityData.get(DATA_SHOULD_BOUNCE) && !this.entityData.get(DATA_IS_BOUNCING)) {
            // 动画将在控制器中播放
        }
    }

    @Override
    public void onSyncedDataUpdated(@NotNull EntityDataAccessor<?> key) {
        super.onSyncedDataUpdated(key);

        // 当弹跳标记被设置时，播放弹跳音效
        if (DATA_SHOULD_BOUNCE.equals(key) && this.entityData.get(DATA_SHOULD_BOUNCE)) {
            // 播放弹跳音效
            this.playSound(SoundEvents.SLIME_JUMP, 0.8f, 1.0f + random.nextFloat() * 0.3f);
        }
    }

    @Override
    public @NotNull Iterable<ItemStack> getArmorSlots() {
        return new ArrayList<>(0);
    }

    @Override
    public @NotNull ItemStack getItemBySlot(@NotNull EquipmentSlot slot) {
        return ItemStack.EMPTY;
    }

    public ItemStack getDroppedItem() {
        // todo 支持附魔
        ItemStack stack = EDGItems.IRON_BALL.get().getDefaultInstance();
        // 如果有附魔，从这里添加
        return stack;
    }

    @Override
    public boolean isInvulnerable() {
        return true;
    }

    @Override
    public boolean isInvulnerableTo(@NotNull DamageSource source) {
        return !source.is(DamageTypes.GENERIC_KILL);
    }

    @Override
    public boolean canDrownInFluidType(FluidType type) {
        return false;
    }

    @Override
    public @NotNull Fallsounds getFallSounds() {
        return new LivingEntity.Fallsounds(SoundEvents.CHAIN_PLACE, SoundEvents.ANVIL_FALL);
    }

    @Override
    public ItemStack getPickedResult(HitResult target) {
        return getDroppedItem();
    }

    @Override
    public boolean isAttackable() {
        return false;
    }

    @Override
    public void setItemSlot(@NotNull EquipmentSlot slot, @NotNull ItemStack stack) {
        // 铁球没有装备槽
    }

    @Override
    public @NotNull HumanoidArm getMainArm() {
        return HumanoidArm.RIGHT;
    }

    @Override
    public void registerControllers(AnimatableManager.@NotNull ControllerRegistrar controllerRegistrar) {
        controllerRegistrar.add(
                new AnimationController<>(this, "bounceController", 5, this::bounceAnimationController)
        );
    }

    private PlayState bounceAnimationController(AnimationState<IronBallEntity> state) {
        // 检查是否需要播放弹跳动画
        if (this.entityData.get(DATA_SHOULD_BOUNCE) && !this.entityData.get(DATA_HAS_BOUNCED)) {
            // 标记正在播放动画
            this.entityData.set(DATA_IS_BOUNCING, true);

            // 播放动画
            state.setAnimation(BOUNCE_ANIM);

            return PlayState.CONTINUE;
        }

        // 动画播放完成
        if (this.entityData.get(DATA_IS_BOUNCING)) {
            // 重置所有弹跳状态
            this.entityData.set(DATA_SHOULD_BOUNCE, false);
            this.entityData.set(DATA_HAS_BOUNCED, true);
            this.entityData.set(DATA_IS_BOUNCING, false);

            // 设置冷却时间，防止连续弹跳
            bounceCooldown = BOUNCE_COOLDOWN_TICKS;
        }

        return PlayState.STOP;
    }

    @Override
    public void addAdditionalSaveData(@NotNull CompoundTag compound) {
        super.addAdditionalSaveData(compound);
        NBTWriter.of(compound)
                .booleanValue(SHOULD_BOUNCE_KEY, this.entityData.get(DATA_SHOULD_BOUNCE))
                .booleanValue(HAS_BOUNCED_KEY, this.entityData.get(DATA_HAS_BOUNCED))
                .booleanValue(IS_BOUNCING_KEY, this.entityData.get(DATA_IS_BOUNCING));
    }

    @Override
    public void readAdditionalSaveData(@NotNull CompoundTag compound) {
        super.readAdditionalSaveData(compound);
        NBTReader.of(compound)
                .booleanValue(SHOULD_BOUNCE_KEY, i -> this.entityData.set(DATA_SHOULD_BOUNCE, i))
                .booleanValue(HAS_BOUNCED_KEY, i -> this.entityData.set(DATA_HAS_BOUNCED, i))
                .booleanValue(IS_BOUNCING_KEY, i -> this.entityData.set(DATA_IS_BOUNCING, i));
    }

    public static AttributeSupplier.Builder createAttributes() {
        return LivingEntity.createLivingAttributes()
                .add(Attributes.MAX_HEALTH, 1.0D)
                .add(Attributes.MOVEMENT_SPEED, 0.0D)
                .add(Attributes.ATTACK_DAMAGE, 0.0D);
    }

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

    /**
     * 手动触发弹跳动画（可用于外部调用）
     */
    public void triggerBounce() {
        if (!this.entityData.get(DATA_HAS_BOUNCED) && bounceCooldown == 0) {
            this.entityData.set(DATA_SHOULD_BOUNCE, true);
        }
    }

    /**
     * 设置最小掉落高度（覆盖配置文件）
     */
    public void setMinFallHeight(int height) {
        // 这个方法可以在需要时扩展
    }
}