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

import com.remains_cave.config.RemainsCaveConfig;
import com.remains_cave.entity.*;
import com.remains_cave.util.ConfigHelper;
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.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
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.List;

public class RuneEntity extends Entity implements GeoEntity {
    private static final EntityDataAccessor<Boolean> DATA_HAS_AURA =
            SynchedEntityData.defineId(RuneEntity.class, EntityDataSerializers.BOOLEAN);

    private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
    private int totalTicks = 0;
    private int effectCount = 0;
    private LivingEntity owner;
    private int initialDelay;
    private int effectInterval;
    private double radius;
    private int maxEffects;
    private float damageAmount;
    private float healAmount;
    private long createTime;
    private int soundTimer = 0; // 音效计时器
    public RuneEntity(EntityType<?> type, Level level) {
        super(type, level);
        this.noCulling = true;
        this.maxEffects = 3;
        this.damageAmount = 4.0f;
        this.healAmount = 2.0f;
        this.initialDelay = 10;
        this.effectInterval = 10;
        this.radius = 1.5;
        this.createTime = level.getGameTime();
    }

    public RuneEntity(Level level, double x, double y, double z, LivingEntity owner,
                      float damageAmount, float healAmount, int maxEffects,
                      int initialDelay, int effectInterval, double radius,
                      boolean hasAura) {
        this(ModEntities.RUNE.get(), level);
        setPos(x, y, z);
        this.owner = owner;
        this.damageAmount = damageAmount;
        this.healAmount = healAmount;
        this.maxEffects = maxEffects;
        this.initialDelay = initialDelay;
        this.effectInterval = Math.max(1, effectInterval);
        this.radius = radius;
        this.createTime = level.getGameTime();
        this.entityData.set(DATA_HAS_AURA, hasAura); // 同步光环状态
    }

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

    @Override
    protected void readAdditionalSaveData(CompoundTag tag) {
        this.totalTicks = tag.getInt("TotalTicks");
        this.effectCount = tag.getInt("EffectCount");
        this.maxEffects = tag.getInt("MaxEffects");
        this.damageAmount = tag.getFloat("DamageAmount");
        this.healAmount = tag.getFloat("HealAmount");
        this.initialDelay = tag.getInt("InitialDelay");
        this.effectInterval = tag.getInt("EffectInterval");
        if (this.effectInterval <= 0) this.effectInterval = 1;
        this.radius = tag.getDouble("Radius");
        if (tag.contains("CreateTime")) {
            this.createTime = tag.getLong("CreateTime");
        } else {
            this.createTime = level().getGameTime();
        }
        // 读取光环状态（如果有存储）
        if (tag.contains("HasAura")) {
            this.entityData.set(DATA_HAS_AURA, tag.getBoolean("HasAura"));
        }
    }

    @Override
    protected void addAdditionalSaveData(CompoundTag tag) {
        tag.putInt("TotalTicks", totalTicks);
        tag.putInt("EffectCount", effectCount);
        tag.putInt("MaxEffects", maxEffects);
        tag.putFloat("DamageAmount", damageAmount);
        tag.putFloat("HealAmount", healAmount);
        tag.putInt("InitialDelay", initialDelay);
        tag.putInt("EffectInterval", effectInterval);
        tag.putDouble("Radius", radius);
        tag.putLong("CreateTime", createTime);
        tag.putBoolean("HasAura", this.entityData.get(DATA_HAS_AURA));
    }

    @Override
    public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
        // 从同步数据获取光环状态（客户端和服务端均使用）
        boolean hasAura = this.entityData.get(DATA_HAS_AURA);
        String prefix = hasAura ? "rune_aura" : "rune";
        RawAnimation sequence = RawAnimation.begin()
                .thenPlay(prefix + "_start")
                .thenPlay(prefix)
                .thenPlay(prefix + "_end");

        AnimationController<RuneEntity> controller = new AnimationController<>(this, "controller", 0, state -> {
            // 首次进入时启动动画
            if (state.getController().getAnimationState() == AnimationController.State.STOPPED) {
                state.setAnimation(sequence);
            }
            return PlayState.CONTINUE;
        });
        controllers.add(controller);
    }

    @Override
    public void tick() {
        super.tick();
        if (level().isClientSide) return;

        // 服务端：动画时长 4 秒 = 80 ticks，到达后销毁实体（额外加5 ticks确保end动画播放完）
        if (level().getGameTime() >= createTime + 85) {
            discard();
            return;
        }

        totalTicks++;

        // 音效逻辑：从 initialDelay 开始，每 10 tick 播放一次 BEACON_POWER_SELECT
        if (totalTicks >= initialDelay) {
            soundTimer++;
            if (soundTimer >= 12) {
                soundTimer = 0;
                level().playSound(null, this.getX(), this.getY(), this.getZ(),
                        SoundEvents.BEACON_POWER_SELECT, this.getSoundSource(), 1.5F, 1.0F);
            }
        }

        // 效果触发（原逻辑）
        if (totalTicks < initialDelay) return;
        if (effectInterval > 0 && (totalTicks - initialDelay) % effectInterval == 0 && effectCount < maxEffects) {
            effectCount++;
            applyEffect();
        }
    }

    private void applyEffect() {
        List<LivingEntity> entities = level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox().inflate(radius));
        for (LivingEntity entity : entities) {
            if (isFriendlySkeleton(entity)) {
                float actualHeal = healAmount;
                if (entity instanceof SkeletonKingEntity) {
                    actualHeal = (float) (healAmount * ConfigHelper.getOrFallback(RemainsCaveConfig.COMMON.warlockKinghealAmount, 1.5));
                }
                entity.heal(actualHeal);
            } else {
                entity.hurt(damageSources().mobAttack(owner), damageAmount);
            }
        }

        // 粒子效果（仅在服务端生成）
        if (level() instanceof ServerLevel serverLevel) {
            for (int i = 0; i < 6; i++) {
                double angle = random.nextDouble() * 2 * Math.PI;
                double r = random.nextDouble() * 1.5;
                double xOffset = Math.cos(angle) * r;
                double zOffset = Math.sin(angle) * r;
                double yOffset = (random.nextDouble() - 0.5);
                serverLevel.sendParticles(ParticleTypes.RAID_OMEN,
                        getX() + xOffset, getY() + 0.5 + yOffset, getZ() + zOffset,
                        1, 0, 0.05, 0, 0);
            }
        }
    }

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

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