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

import com.remains_cave.attribute.ModAttributes;
import com.remains_cave.config.RemainsCaveConfig;
import com.remains_cave.effect.ModEffects;
import com.remains_cave.entity.ai.CustomAttackGoal;
import com.remains_cave.entity.ai.StayNearKingGoal;
import com.remains_cave.entity.ai.TeamHurtByTargetGoal;
import com.remains_cave.util.ConfigHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.BlockParticleOption;
import net.minecraft.core.particles.ParticleTypes;
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.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.*;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Scoreboard;
import org.jetbrains.annotations.NotNull;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.*;
import software.bernie.geckolib.util.GeckoLibUtil;

import java.util.Objects;

public class SkeletonWarriorEntity extends Monster implements GeoEntity, AuraBearer {
    // 同步数据
    private static final EntityDataAccessor<Boolean> DATA_HAS_AURA = SynchedEntityData.defineId(SkeletonWarriorEntity.class, EntityDataSerializers.BOOLEAN);
    private static final EntityDataAccessor<Boolean> DATA_IS_SUMMONING = SynchedEntityData.defineId(SkeletonWarriorEntity.class, EntityDataSerializers.BOOLEAN);

    private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
    private static final RawAnimation IDLE = RawAnimation.begin().thenLoop("animation.skeleton_warrior.idle");
    private static final RawAnimation WALK = RawAnimation.begin().thenLoop("animation.skeleton_warrior.walk");
    private static final RawAnimation ATTACK = RawAnimation.begin().thenPlay("animation.skeleton_warrior.attack");
    private static final RawAnimation HURT = RawAnimation.begin().thenPlay("animation.skeleton_warrior.idle2");
    private static final RawAnimation SUMMON = RawAnimation.begin().thenPlay("summon");
    private float summonYaw = 0;  // 存储召唤时的随机朝向
    private int stunTimer = 0;
    private boolean isHurt = false;
    private int hurtTimer = 0;
    private boolean ignoreHurtEffects = false;
    private boolean hasJoinedTeam = false;
    private int summonAnimationTimer = 0;          // 服务端计时器
    private boolean hasPlayedSummonAnim = false;   // 持久化标志，防止重进重复播放
    private int particleTick = 0;                   // 粒子计数器

    public boolean isSummoning() {
        if (level().isClientSide) {
            return this.entityData.get(DATA_IS_SUMMONING);
        } else {
            return summonAnimationTimer > 0;
        }
    }

    public boolean isStunned() {
        return stunTimer > 0;
    }

    public void startSummonAnimation() {
        if (level().isClientSide) return;
        summonAnimationTimer = 40;
        summonYaw = random.nextFloat() * 360.0f;
        this.setYRot(summonYaw);
        this.setYBodyRot(summonYaw);
        this.setYHeadRot(summonYaw);
        this.entityData.set(DATA_IS_SUMMONING, true);
        // 清除 AI 状态，但不调用 LookControl.setLookAt(null)
        this.setTarget(null);
        this.getNavigation().stop();
        this.getMoveControl().setWantedPosition(this.getX(), this.getY(), this.getZ(), 0.0);
        this.setDeltaMovement(Vec3.ZERO);
    }

    public SkeletonWarriorEntity(EntityType<? extends Monster> type, Level level) {
        super(type, level);
        Objects.requireNonNull(this.getAttribute(ModAttributes.SMITE_RESISTANCE))
                .setBaseValue(RemainsCaveConfig.COMMON.warriorSmiteResistance.get());
    }

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

    @Override
    public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
        AnimationController<SkeletonWarriorEntity> controller = new AnimationController<>(this, "controller", 2, this::animationPredicate)
                .triggerableAnim("attack", ATTACK)
                .triggerableAnim("hurt", HURT)
                .triggerableAnim("summon", SUMMON);
        controllers.add(controller);
    }

    private PlayState animationPredicate(AnimationState<SkeletonWarriorEntity> state) {
        if (isSummoning()) {
            return PlayState.CONTINUE;
        }
        if (isHurt) {
            return PlayState.CONTINUE;
        }
        if (state.isMoving()) {
            return state.setAndContinue(WALK);
        }
        return state.setAndContinue(IDLE);
    }

    public void triggerAttackAnim() {
        this.triggerAnim("controller", "attack");
    }

    public void setIgnoreHurtEffects(boolean ignore) {
        this.ignoreHurtEffects = ignore;
    }

    @Override
    protected void defineSynchedData(SynchedEntityData.@NotNull Builder builder) {
        super.defineSynchedData(builder);
        builder.define(DATA_HAS_AURA, false);
        builder.define(DATA_IS_SUMMONING, false);
    }

    @Override
    public void addAdditionalSaveData(@NotNull CompoundTag tag) {
        super.addAdditionalSaveData(tag);
        tag.putInt("SummonTimer", summonAnimationTimer);
        tag.putBoolean("HasPlayedSummonAnim", hasPlayedSummonAnim);
    }

    @Override
    public void readAdditionalSaveData(@NotNull CompoundTag tag) {
        super.readAdditionalSaveData(tag);
        summonAnimationTimer = tag.getInt("SummonTimer");
        hasPlayedSummonAnim = tag.getBoolean("HasPlayedSummonAnim");
        if (summonAnimationTimer > 0) {
            this.entityData.set(DATA_IS_SUMMONING, true);
        }
    }

    @Override
    public void performRangedAttack(LivingEntity target, float distanceFactor) { }

    @Override
    public boolean hasAura() {
        return this.entityData.get(DATA_HAS_AURA);
    }

    public void setHasAura(boolean hasAura) {
        this.entityData.set(DATA_HAS_AURA, hasAura);
    }

    @Override
    public void tick() {
        if (!level().isClientSide && this.getTarget() instanceof Player player && player.isCreative()) {
            this.setTarget(null);
            this.setLastHurtByMob(null);
        }
        super.tick();

        // ========== 服务端逻辑 ==========
        if (!level().isClientSide) {
            // 召唤动画计时
            if (summonAnimationTimer > 0) {
                summonAnimationTimer--;
                if (summonAnimationTimer <= 0) {
                    this.entityData.set(DATA_IS_SUMMONING, false);
                }
            }
            // 动画期间强制静止
            if (isSummoning()) {
                this.setYRot(summonYaw);
                this.setYBodyRot(summonYaw);
                this.setYHeadRot(summonYaw);

                this.setTarget(null);
                this.getNavigation().stop();
                this.getMoveControl().setWantedPosition(this.getX(), this.getY(), this.getZ(), 0.0);
                this.setDeltaMovement(Vec3.ZERO);
            }

            if (stunTimer > 0) stunTimer--;
            if (hurtTimer > 0) {
                hurtTimer--;
                if (hurtTimer <= 0) isHurt = false;
            }

            boolean aura = this.hasEffect(ModEffects.KINGS_AURA);
            setHasAura(aura);
            if (!hasJoinedTeam) {
                Scoreboard scoreboard = level().getScoreboard();
                PlayerTeam team = scoreboard.getPlayerTeam("skeleton_army");
                if (team == null) {
                    team = scoreboard.addPlayerTeam("skeleton_army");
                    team.setAllowFriendlyFire(false);
                }
                if (this.getTeam() == null) {
                    scoreboard.addPlayerToTeam(this.getScoreboardName(), team);
                }
                hasJoinedTeam = true;
            }
        }

        // ========== 客户端逻辑 ==========
        if (level().isClientSide) {
            boolean summoningFlag = this.entityData.get(DATA_IS_SUMMONING);
            if (!hasPlayedSummonAnim && summoningFlag) {
                this.triggerAnim("controller", "summon");
                hasPlayedSummonAnim = true;
            }

            // 粒子效果
            if (isSummoning()) {
                particleTick++;
                if (particleTick >= 1) {
                    particleTick = 0;
                    BlockPos belowPos = this.blockPosition().below();
                    BlockState belowState = level().getBlockState(belowPos);
                    level().addParticle(new BlockParticleOption(ParticleTypes.BLOCK, belowState),
                            this.getX(), this.getY() + 0.1, this.getZ(),
                            (random.nextDouble() - 0.5) * 0.3,
                            random.nextDouble() * 0.2,
                            (random.nextDouble() - 0.5) * 0.3);
                }
            }
        }
    }

    // 修改 hurt() 方法，增加 KINGS_AURA 减伤
    @Override
    public boolean hurt(@NotNull DamageSource source, float amount) {
        Vec3 originalVelocity = null;
        if (isSummoning()) {
            amount *= 0.2f;
            originalVelocity = this.getDeltaMovement();
        }

        // 新增：若拥有 KINGS_AURA，减少 40% 伤害
        if (this.hasEffect(ModEffects.KINGS_AURA)) {
            amount *= 0.6f;
        }

        boolean hurt = super.hurt(source, amount);
        if (hurt && !level().isClientSide) {
            if (isSummoning()) {
                if (originalVelocity != null) {
                    this.setDeltaMovement(originalVelocity);
                }
            } else if (!ignoreHurtEffects) {
                this.triggerAnim("controller", "hurt");
                isHurt = true;
                hurtTimer = 12;
                stunTimer = 10;
            }
        }
        ignoreHurtEffects = false;
        return hurt;
    }

    @Override
    public void knockback(double strength, double x, double z) {
        if (!isSummoning()) {
            super.knockback(strength, x, z);
        }
    }

    @Override
    protected void registerGoals() {
        this.goalSelector.addGoal(0, new FloatGoal(this));
        this.goalSelector.addGoal(2, new CustomAttackGoal(this, 1.0D, 25, 3) {
            @Override
            public boolean canUse() {
                if (SkeletonWarriorEntity.this.isSummoning()) return false;
                return super.canUse();
            }
            @Override
            public boolean canContinueToUse() {
                if (SkeletonWarriorEntity.this.isSummoning()) return false;
                return super.canContinueToUse();
            }
        });
        this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 0.8D, (float)0.0001));
        this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
        this.goalSelector.addGoal(3, new StayNearKingGoal(this, 1.0D, 9.0, 6.0) {
            @Override
            public boolean canUse() {
                if (SkeletonWarriorEntity.this.isSummoning()) return false;
                return super.canUse();
            }
            @Override
            public boolean canContinueToUse() {
                if (SkeletonWarriorEntity.this.isSummoning()) return false;
                return super.canContinueToUse();
            }
        });
        this.targetSelector.addGoal(0, new TeamHurtByTargetGoal(this, true));
        this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
    }

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

    public static AttributeSupplier.Builder createAttributes() {
        return Monster.createMonsterAttributes()
                .add(Attributes.MAX_HEALTH, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warriorMaxHealth, 30.0))
                .add(Attributes.MOVEMENT_SPEED, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warriorMovementSpeed, 0.33))
                .add(Attributes.ARMOR, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warriorArmor, 15.0))
                .add(Attributes.ARMOR_TOUGHNESS, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warriorArmorToughness, 15.0))
                .add(Attributes.ATTACK_DAMAGE, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warriorAttackDamage, 10.0))
                .add(Attributes.KNOCKBACK_RESISTANCE, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warriorKnockbackResistance, 0.3))
                .add(Attributes.FOLLOW_RANGE, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warriorFollowRange, 25.0))
                .add(ModAttributes.SMITE_RESISTANCE);
    }

    @Override
    protected int getBaseExperienceReward() {
        return (int)this.getMaxHealth();
    }

    @Override
    protected @NotNull SoundEvent getHurtSound(@NotNull DamageSource damageSource) {
        return SoundEvents.SKELETON_HURT;
    }

    @Override
    protected @NotNull SoundEvent getDeathSound() {
        return SoundEvents.SKELETON_DEATH;
    }

    @Override
    protected SoundEvent getAmbientSound() {
        return SoundEvents.SKELETON_AMBIENT;
    }
}