/*
 * 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.block.ModBlocks;
import com.remains_cave.block.SkeletonKingRemainsBlock;
import com.remains_cave.block.SkeletonKingSummonBlock;
import com.remains_cave.block.entity.SkeletonKingRemainsBlockEntity;
import com.remains_cave.block.entity.SkeletonKingSummonBlockEntity;
import com.remains_cave.config.RemainsCaveConfig;
import com.remains_cave.dungeon.room.RoomManager;
import com.remains_cave.effect.ModEffects;
import com.remains_cave.entity.ai.*;
import com.remains_cave.util.ConfigHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerBossEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.tags.DamageTypeTags;
import net.minecraft.world.BossEvent;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
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.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Scoreboard;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3f;
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.ArrayList;
import java.util.List;
import java.util.Objects;

public class SkeletonKingEntity extends Monster implements GeoEntity {
    private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
    private final ServerBossEvent bossEvent = new ServerBossEvent(
            this.getDisplayName(),
            BossEvent.BossBarColor.RED,
            BossEvent.BossBarOverlay.NOTCHED_10
    );

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

    private BlockPos summonBlockPos;
    private Direction summonBlockFacing;
    private int noTargetTimer = 0;
    private static final int NO_TARGET_TIMEOUT = 600; // 30秒
    private boolean shouldRestoreBlock = false;

    public void setSummonBlockInfo(BlockPos pos, Direction facing) {
        this.summonBlockPos = pos;
        this.summonBlockFacing = facing;
    }

    // 动画定义
    private static final RawAnimation IDLE = RawAnimation.begin().thenLoop("animation.skeleton_king.idle");
    private static final RawAnimation WALK = RawAnimation.begin().thenLoop("animation.skeleton_king.walk");
    private static final RawAnimation ATTACK = RawAnimation.begin().thenPlay("animation.skeleton_king.attack");
    private static final RawAnimation DASH = RawAnimation.begin().thenPlay("animation.skeleton_king.dash");
    private static final RawAnimation SUMMON = RawAnimation.begin().thenPlay("animation.skeleton_king.summon");
    private static final RawAnimation DEATH = RawAnimation.begin().thenPlay("death");

    private boolean hasJoinedTeam = false;
    private BlockPos remainsPos;
    private Direction remainsFacing;
    private boolean fromRemains = false;

    public void setRemainsInfo(BlockPos pos, Direction facing) {
        this.remainsPos = pos;
        this.remainsFacing = facing;
    }

    public void setIsFromRemains(boolean fromRemains) {
        this.fromRemains = fromRemains;
    }
    private float lockedYaw;   // 死亡动画期间锁定的偏航角
    private float lockedPitch; // 死亡动画期间锁定的俯仰角
    // 冷却字段
    private int attackCooldown = 0;
    private int dashCooldown = 0;
    private int summonCooldown = 0;
    private int auraScanTimer = 0;

    private int deathAnimationTimer = 0;
    private static final int DEATH_ANIMATION_LENGTH = 33; // 2秒

    private boolean firstSummonDone = false;   // 是否已完成首次召唤
    public boolean isFirstSummonDone() { return !firstSummonDone; }
    public void setFirstSummonDone(boolean done) { this.firstSummonDone = done; }

    private boolean isDashing = false;
    private boolean isSummoning = false;

    public boolean isDashing() { return isDashing; }
    public void setDashing(boolean dashing) { isDashing = dashing; }
    public boolean isSummoning() { return isSummoning; }
    public void setSummoning(boolean summoning) { isSummoning = summoning; }

    public SkeletonKingEntity(EntityType<? extends Monster> type, Level level) {
        super(type, level);
        bossEvent.setDarkenScreen(false);
        this.bossEvent.setName(Component.literal("Skeleton King"));
        Objects.requireNonNull(this.getAttribute(ModAttributes.SMITE_RESISTANCE))
                .setBaseValue(RemainsCaveConfig.COMMON.kingSmiteResistance.get());
    }

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

    @Override
    public void startSeenByPlayer(@NotNull ServerPlayer player) {
        super.startSeenByPlayer(player);
        this.bossEvent.addPlayer(player);
    }

    @Override
    public void stopSeenByPlayer(@NotNull ServerPlayer player) {
        super.stopSeenByPlayer(player);
        this.bossEvent.removePlayer(player);
    }

    @Override
    public void remove(@NotNull RemovalReason reason) {
        if (!level().isClientSide) {
            this.bossEvent.removeAllPlayers();
        }
        // 如果是从遗骸召唤且因无目标超时而移除，则在原位置生成遗骸方块
        if (!level().isClientSide && shouldRestoreBlock && fromRemains && remainsPos != null) {
            BlockState state = ModBlocks.SKELETON_KING_REMAINS.get().defaultBlockState();
            if (remainsFacing != null) {
                state = state.setValue(SkeletonKingRemainsBlock.FACING, remainsFacing);
            }
            level().setBlock(remainsPos, state, Block.UPDATE_ALL);
            // 将房间ID写入遗骸方块的BlockEntity
            if (!roomId.isEmpty()) {
                BlockEntity be = level().getBlockEntity(remainsPos);
                if (be instanceof SkeletonKingRemainsBlockEntity remainsBE) {
                    remainsBE.setRoomId(roomId);
                    remainsBE.setChanged();
                    if (level() instanceof ServerLevel serverLevel) {
                        serverLevel.getChunkSource().blockChanged(remainsPos);
                    }
                }
            }
            // 解锁门
            if (!roomId.isEmpty() && level() instanceof ServerLevel serverLevel) {
                RoomManager.get(level()).deactivateBoss(roomId, serverLevel);
            }
        } else if (!level().isClientSide && shouldRestoreBlock && summonBlockPos != null) {
            // 普通召唤方块恢复逻辑
            BlockState state = ModBlocks.SKELETON_KING_SUMMON.get().defaultBlockState();
            if (summonBlockFacing != null) {
                state = state.setValue(SkeletonKingSummonBlock.FACING, summonBlockFacing);
            }
            level().setBlock(summonBlockPos, state, Block.UPDATE_ALL);
            // 将房间ID写入召唤方块的BlockEntity
            if (!roomId.isEmpty()) {
                BlockEntity be = level().getBlockEntity(summonBlockPos);
                if (be instanceof SkeletonKingSummonBlockEntity summonBE) {
                    summonBE.setRoomId(roomId);
                    summonBE.setChanged();
                    if (level() instanceof ServerLevel serverLevel) {
                        serverLevel.getChunkSource().blockChanged(summonBlockPos);
                    }
                }
            }
            // 解锁门
            if (!roomId.isEmpty() && level() instanceof ServerLevel serverLevel) {
                RoomManager.get(level()).deactivateBoss(roomId, serverLevel);
            }
        }
        super.remove(reason);
    }

    @Override
    public void addAdditionalSaveData(@NotNull CompoundTag tag) {
        super.addAdditionalSaveData(tag);
        tag.putBoolean("FirstSummonDone", firstSummonDone);
        if (summonBlockPos != null) {
            tag.putLong("SummonBlockPos", summonBlockPos.asLong());
        }
        if (summonBlockFacing != null) {
            tag.putInt("SummonBlockFacing", summonBlockFacing.ordinal());
        }
        tag.putInt("NoTargetTimer", noTargetTimer);
        tag.putBoolean("ShouldRestoreBlock", shouldRestoreBlock);
        tag.putBoolean("FromRemains", fromRemains);
        if (remainsPos != null) {
            tag.putLong("RemainsPos", remainsPos.asLong());
        }
        if (remainsFacing != null) {
            tag.putInt("RemainsFacing", remainsFacing.ordinal());
        }
        tag.putString("RoomId", roomId);
    }

    @Override
    public void readAdditionalSaveData(@NotNull CompoundTag tag) {
        super.readAdditionalSaveData(tag);
        firstSummonDone = tag.getBoolean("FirstSummonDone");
        if (tag.contains("SummonBlockPos")) {
            summonBlockPos = BlockPos.of(tag.getLong("SummonBlockPos"));
        }
        if (tag.contains("SummonBlockFacing")) {
            summonBlockFacing = Direction.values()[tag.getInt("SummonBlockFacing")];
        }
        noTargetTimer = tag.getInt("NoTargetTimer");
        shouldRestoreBlock = tag.getBoolean("ShouldRestoreBlock");
        fromRemains = tag.getBoolean("FromRemains");
        if (tag.contains("RemainsPos")) {
            remainsPos = BlockPos.of(tag.getLong("RemainsPos"));
        }
        if (tag.contains("RemainsFacing")) {
            remainsFacing = Direction.values()[tag.getInt("RemainsFacing")];
        }
        roomId = tag.getString("RoomId");
    }

    private void summonInitialMinions(PlayerTeam team) {
        List<EntityType<? extends Mob>> types = List.of(
                ModEntities.SKELETON_WARRIOR.get(),
                ModEntities.SKELETON_ARCHER.get(),
                ModEntities.SKELETON_WARLOCK.get()
        );
        for (int i = 0; i < types.size(); i++) {
            EntityType<? extends Mob> type = types.get(i);
            double angle = i * (2 * Math.PI / 3);
            double radius = 2.5;
            double dx = Math.cos(angle) * radius;
            double dz = Math.sin(angle) * radius;
            double x = this.getX() + dx;
            double y = this.getY();
            double z = this.getZ() + dz;

            Mob mob = type.create(level());
            if (mob != null) {
                mob.setPos(x, y, z);
                mob.setTarget(this.getTarget());
                level().getScoreboard().addPlayerToTeam(mob.getScoreboardName(), team);
                level().addFreshEntity(mob);
            }
        }
    }

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

        // ========== 死亡动画阶段 ==========
        if (deathAnimationTimer > 0) {
            // 每帧强制设置速度和旋转角度
            this.setDeltaMovement(Vec3.ZERO);
            this.setYRot(this.lockedYaw);
            this.setXRot(this.lockedPitch);
            this.yHeadRot = this.lockedYaw;   // 同步头部旋转

            deathAnimationTimer--;
            if (deathAnimationTimer == 0) {
                this.setInvulnerable(false);
                // 生成遗骸方块
                BlockPos deathPos = this.blockPosition();
                float yaw = this.lockedYaw;
                Direction facing = Direction.fromYRot(yaw);
                BlockState state = ModBlocks.SKELETON_KING_REMAINS.get().defaultBlockState()
                        .setValue(SkeletonKingRemainsBlock.FACING, facing);
                level().setBlock(deathPos, state, Block.UPDATE_ALL);

                // 将房间ID写入遗骸方块的BlockEntity
                if (!roomId.isEmpty()) {
                    BlockEntity be = level().getBlockEntity(deathPos);
                    if (be instanceof SkeletonKingRemainsBlockEntity remainsBE) {
                        remainsBE.setRoomId(roomId);
                        remainsBE.setChanged();
                        // 同步到客户端
                        if (level() instanceof ServerLevel serverLevel) {
                            serverLevel.getChunkSource().blockChanged(deathPos);
                        }
                    }
                }
                // 移除实体
                this.discard();
            }
            return; // 动画期间不执行其他 AI 逻辑
        }

        // ========== 正常 AI 逻辑（仅当未死亡时）==========
        if (!level().isClientSide) {
            // 无目标计时
            LivingEntity target = getTarget();
            if (target == null || !target.isAlive()) {
                noTargetTimer++;
                if (noTargetTimer >= NO_TARGET_TIMEOUT) {
                    shouldRestoreBlock = true;
                    this.discard();
                    return;
                }
            } else {
                noTargetTimer = 0;
            }

            // 更新BossBar进度
            this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());

            // 冷却递减
            if (dashCooldown > 0) dashCooldown--;
            if (summonCooldown > 0) summonCooldown--;
            if (attackCooldown > 0) attackCooldown--;

            // 光环扫描
            if (--auraScanTimer <= 0) {
                auraScanTimer = 40;
                applyAuraToNearbySkeletons();
            }

            // 队伍加入（仅执行一次）
            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 && tickCount % 5 == 0) {
            AABB area = getBoundingBox().inflate(26, 5, 26);
            List<SkeletonArcherEntity> archers = level().getEntitiesOfClass(
                    SkeletonArcherEntity.class,
                    area,
                    archer -> archer.isAlive() && archer.hasEffect(ModEffects.KINGS_AURA)
            );

            if (!archers.isEmpty()) {
                List<MobEffectInstance> harmfulEffects = new ArrayList<>();
                for (MobEffectInstance effect : this.getActiveEffects()) {
                    if (!effect.getEffect().value().isBeneficial()) {
                        harmfulEffects.add(effect);
                    }
                }

                for (MobEffectInstance effect : harmfulEffects) {
                    SkeletonArcherEntity targetArcher = archers.get(random.nextInt(archers.size()));

                    if (level() instanceof ServerLevel serverLevel) {
                        int effectColor = effect.getEffect().value().getColor();
                        float r = ((effectColor >> 16) & 0xFF) / 255.0f;
                        float g = ((effectColor >> 8) & 0xFF) / 255.0f;
                        float b = (effectColor & 0xFF) / 255.0f;
                        DustParticleOptions dustOption = new DustParticleOptions(new Vector3f(r, g, b), 0.5f);

                        Vec3 kingPos = position();
                        Vec3 archerPos = targetArcher.position();
                        Vec3 direction = archerPos.subtract(kingPos).normalize();
                        double distance = kingPos.distanceTo(archerPos);
                        int steps = Math.max(3, (int)(distance * 2));

                        for (int i = 1; i <= steps; i++) {
                            double factor = i / (double) steps;
                            Vec3 point = kingPos.add(direction.scale(distance * factor));
                            serverLevel.sendParticles(
                                    dustOption,
                                    point.x, point.y + 0.5, point.z,
                                    1, 0, 0, 0, 0
                            );
                        }
                    }

                    targetArcher.addEffect(new MobEffectInstance(effect));
                    this.removeEffect(effect.getEffect());
                }
            }
        }
    }

    // ========== 死亡逻辑接管 ==========
    @Override
    public boolean hurt(@NotNull DamageSource source, float amount) {
        if (this.isInvulnerableTo(source)) {
            return false;
        }
        if (deathAnimationTimer > 0) {
            return false;
        }

        // 简化的致死判断：当前生命值 ≤ 原始伤害（实际游戏中无需非常精确）
        if (this.getHealth() <= amount) {
            handleDeath(source);
            return true;
        }

        // 是否转移伤害（只有非致死伤害才进入转移逻辑）
        boolean shouldTransfer = !source.is(DamageTypeTags.IS_FIRE) && !source.is(DamageTypeTags.WITCH_RESISTANT_TO);
        float beforeHealth = getHealth();
        boolean result;

        if (shouldTransfer) {
            AABB area = getBoundingBox().inflate(18, 5, 18);
            List<SkeletonWarriorEntity> warriors = level().getEntitiesOfClass(
                    SkeletonWarriorEntity.class,
                    area,
                    warrior -> warrior.isAlive() && warrior.hasEffect(ModEffects.KINGS_AURA)
            );

            if (!warriors.isEmpty()) {
                result = super.hurt(source, amount / 2);
                float afterHealth = getHealth();
                float actualDamage = beforeHealth - afterHealth;
                if (actualDamage > 0) {
                    float warriorShare = (amount / 2) / warriors.size();
                    for (SkeletonWarriorEntity warrior : warriors) {
                        warrior.setIgnoreHurtEffects(true);
                        warrior.hurt(source, warriorShare);
                        // 粒子效果（保持原有代码）
                        if (level() instanceof ServerLevel serverLevel) {
                            Vec3 kingPos = position();
                            Vec3 warriorPos = warrior.position();
                            Vec3 direction = warriorPos.subtract(kingPos).normalize();
                            double distance = kingPos.distanceTo(warriorPos);
                            int steps = Math.max(2, (int) (distance));
                            for (int i = 1; i <= steps; i++) {
                                double factor = i / (double) steps;
                                Vec3 point = kingPos.add(direction.scale(distance * factor));
                                serverLevel.sendParticles(ParticleTypes.DAMAGE_INDICATOR, point.x, point.y + 0.5, point.z, 1, 0, 0, 0, 0);
                            }
                        }
                    }
                }
            } else {
                result = super.hurt(source, amount);
            }
        } else {
            result = super.hurt(source, amount);
        }

        // 兜底：如果 super.hurt 后生命归零（比如护甲抵消后仍然致死），也进入死亡流程
        if (this.getHealth() <= 0 && !this.isDeadOrDying()) {
            handleDeath(source);
        }
        return result;
    }

    /**
     * 完全接管死亡流程：触发动画、生成遗骸、清理房间等
     */
    private void handleDeath(DamageSource source) {
        if (this.isDeadOrDying()) return;

        // 解锁其他房间
        if (!level().isClientSide && !roomId.isEmpty()) {
            RoomManager roomManager = RoomManager.get(level());
            roomManager.unlockAllRoomsExcept(roomId, level());
        }

        // 掉落战利品
        if (level() instanceof ServerLevel serverLevel) {
            super.dropAllDeathLoot(serverLevel, source);
        }

        // 通知房间管理器 Boss 死亡
        if (!level().isClientSide && !roomId.isEmpty() && level() instanceof ServerLevel serverLevel) {
            RoomManager.get(level()).deactivateBoss(roomId, serverLevel);
        }

        // 触发死亡动画
        this.triggerAnim("controller", "death");
        this.deathAnimationTimer = DEATH_ANIMATION_LENGTH;
        this.setInvulnerable(true);
        this.setNoActionTime(DEATH_ANIMATION_LENGTH);
        this.lockedYaw = this.getYRot();
        this.lockedPitch = this.getXRot();
        this.setDeltaMovement(Vec3.ZERO);
        this.playSound(this.getDeathSound(), 1.0F, 1.0F);
    }

    @Override
    public void die(@NotNull DamageSource source) {
        // 空实现，防止原版死亡流程被意外触发（因为我们已经完全接管）
    }

    // ========== 光环等辅助方法 ==========
    private void applyAuraToNearbySkeletons() {
        AABB area = getBoundingBox().inflate(18);
        List<LivingEntity> entities = level().getEntitiesOfClass(LivingEntity.class, area,
                e -> e != this && isFriendlySkeleton(e));
        for (LivingEntity skeleton : entities) {
            skeleton.addEffect(new MobEffectInstance(ModEffects.KINGS_AURA, 100, 0, false, false, false));
        }
    }

    private boolean isFriendlySkeleton(LivingEntity entity) {
        return entity instanceof SkeletonWarriorEntity ||
                entity instanceof SkeletonArcherEntity ||
                entity instanceof SkeletonWarlockEntity;
    }

    // Getter / Setter for cooldowns
    public int getAttackCooldown() { return attackCooldown; }
    public void setAttackCooldown(int cooldown) { this.attackCooldown = cooldown; }
    public int getDashCooldown() { return dashCooldown; }
    public void setDashCooldown(int cooldown) { this.dashCooldown = cooldown; }
    public int getSummonCooldown() { return summonCooldown; }
    public void setSummonCooldown(int cooldown) { this.summonCooldown = cooldown; }

    public boolean isEnraged() {
        return this.getHealth() / this.getMaxHealth() < RemainsCaveConfig.COMMON.enrageThreshold.get();
    }

    // 动画触发器
    public void triggerAttackAnim() { this.triggerAnim("controller", "attack"); }
    public void triggerDashAnim()   { this.triggerAnim("controller", "dash"); }
    public void triggerSummonAnim() { this.triggerAnim("controller", "summon"); }

    @Override
    public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
        controllers.add(new AnimationController<>(this, "controller", 2, this::animationPredicate)
                .triggerableAnim("attack", ATTACK)
                .triggerableAnim("dash", DASH)
                .triggerableAnim("summon", SUMMON)
                .triggerableAnim("death", DEATH));
    }

    private PlayState animationPredicate(AnimationState<SkeletonKingEntity> state) {
        if (state.isMoving()) {
            return state.setAndContinue(WALK);
        }
        return state.setAndContinue(IDLE);
    }

    @Override
    protected void registerGoals() {
        this.goalSelector.addGoal(0, new FloatGoal(this));
        this.goalSelector.addGoal(1, new KingDashGoal(this));
        this.goalSelector.addGoal(2, new KingSummonGoal(this));
        this.goalSelector.addGoal(3, new KingAttackGoal(this, 1.0D, RemainsCaveConfig.COMMON.attackCooldown.get(), 6));
        this.goalSelector.addGoal(4, new WaterAvoidingRandomStrollGoal(this, 0.8D, 0.0f));
        this.goalSelector.addGoal(5, new RandomLookAroundGoal(this));

        this.targetSelector.addGoal(0, new TeamHurtByTargetGoal(this, true));
        this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
    }

    public static AttributeSupplier.Builder createAttributes() {
        return Monster.createMonsterAttributes()
                .add(Attributes.MAX_HEALTH, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.maxHealth, 200.0))
                .add(Attributes.MOVEMENT_SPEED, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.movementSpeed, 0.25))
                .add(Attributes.ARMOR, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.armor, 18.0))
                .add(Attributes.ARMOR_TOUGHNESS, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.armortoughness, 9.0))
                .add(Attributes.ATTACK_DAMAGE, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.attackDamage, 20.0))
                .add(Attributes.KNOCKBACK_RESISTANCE, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.knockbackResistance, 1.0))
                .add(Attributes.FOLLOW_RANGE, ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.followRange, 32.0))
                .add(ModAttributes.SMITE_RESISTANCE);
    }

    @Override
    protected int getBaseExperienceReward() {
        return (int) (300 + (int)this.getMaxHealth()*0.5);
    }

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

    @Override
    protected @NotNull SoundEvent getHurtSound(@NotNull DamageSource source) {
        return SoundEvents.WITHER_SKELETON_HURT;
    }

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

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