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

import com.remains_cave.config.RemainsCaveConfig;
import com.remains_cave.entity.*;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.sounds.SoundEvents;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;

public class KingSummonGoal extends Goal {
    private final SkeletonKingEntity king;
    private int phaseTimer = 0;
    private int phase = 0; // 0=未激活,1=前摇,2=后摇
    private static final int WINDUP_TICKS = 10;
    private static final int RECOVERY_TICKS = 20;
    private final Random random = new Random();
    private boolean soundPlayed = false;

    public KingSummonGoal(SkeletonKingEntity king) {
        this.king = king;
        this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
    }

    /** 获取当前队伍中已存在的召唤骷髅数量（不包括骷髅王自己） */
    private int getCurrentSummonCount() {
        Level level = king.level();
        Scoreboard scoreboard = level.getScoreboard();
        String teamName = "skeleton_army";
        PlayerTeam team = scoreboard.getPlayerTeam(teamName);
        if (team == null) return 0;
        int count = 0;
        List<Mob> allMobs = level.getEntitiesOfClass(Mob.class, king.getBoundingBox().inflate(32));
        for (Mob mob : allMobs) {
            if (mob != king && mob.getTeam() != null && mob.getTeam().equals(team)) {
                count++;
            }
        }
        return count;
    }

    /** 根据是否狂暴返回最大召唤数量上限（从配置文件读取） */
    private int getMaxSummons() {
        if (king.isEnraged()) {
            return RemainsCaveConfig.COMMON.summonMaxCountEnraged.get();
        } else {
            return RemainsCaveConfig.COMMON.summonMaxCount.get();
        }
    }

    @Override
    public boolean canUse() {
        if (king.isDashing()) return false;
        if (king.getSummonCooldown() > 0) return false;
        LivingEntity target = king.getTarget();
        if (target == null || !target.isAlive()) return false;
        // 首次召唤不受数量限制
        if (king.isFirstSummonDone()) {
            return true;
        }
        return getCurrentSummonCount() < getMaxSummons();
    }

    @Override
    public boolean canContinueToUse() {
        return phase != 0 && phaseTimer > 0;
    }

    @Override
    public void start() {
        phase = 1;
        phaseTimer = WINDUP_TICKS;
        king.triggerSummonAnim();
        king.setSummoning(true);
        soundPlayed = false;
    }

    @Override
    public void tick() {
        if (phase == 0) return;

        phaseTimer--;

        if (phase == 1) {
            LivingEntity target = king.getTarget();
            if (target != null) {
                king.getLookControl().setLookAt(target, 30, 30);
            }
            if (!soundPlayed) {
                king.level().playSound(null, king.getX(), king.getY(), king.getZ(),
                        SoundEvents.WARDEN_ROAR, king.getSoundSource(), 1.0F, 1.0F);
                soundPlayed = true;
            }
            if (phaseTimer <= 0) {
                if (king.isFirstSummonDone()) {
                    summonAllTypesOneEach();
                    king.setFirstSummonDone(true);
                } else {
                    summonMinions();
                }
                phase = 2;
                phaseTimer = RECOVERY_TICKS;
            }
        } else if (phase == 2) {
            LivingEntity target = king.getTarget();
            if (target != null) {
                king.getLookControl().setLookAt(target, 30, 30);
            }
            if (phaseTimer <= 0) {
                phase = 0;
                king.setSummonCooldown(getCurrentCooldown());
            }
        }
    }

    @Override
    public void stop() {
        if (phase != 0 && king.getSummonCooldown() == 0) {
            king.setSummonCooldown(getCurrentCooldown() / 2);
        }
        phase = 0;
        phaseTimer = 0;
        king.setSummoning(false);
    }

    /** 根据是否暴怒返回实际冷却时间 */
    private int getCurrentCooldown() {
        int baseCooldown = RemainsCaveConfig.COMMON.summonCooldown.get();
        if (king.isEnraged()) {
            return (int) (baseCooldown * 0.75);
        }
        return baseCooldown;
    }

    /**
     * 检查从国王眼睛到目标位置是否视线畅通（无方块阻挡）
     */
    private boolean hasLineOfSight(BlockPos targetPos) {
        Level level = king.level();
        Vec3 start = king.getEyePosition();
        Vec3 end = Vec3.atCenterOf(targetPos);
        double distance = start.distanceTo(end);
        ClipContext context = new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, king);
        BlockHitResult hit = level.clip(context);
        if (hit.getType() == HitResult.Type.MISS) {
            return true;
        }
        // 如果命中点距离起点小于目标距离，说明在到达目标前就碰到了方块
        return hit.getLocation().distanceTo(start) >= distance - 0.01;
    }

    /** 寻找合适的召唤位置（优先砂土，且不为固体，在视线内，且未被占用） */
    private BlockPos findValidSummonPosition(List<BlockPos> occupiedPositions) {
        Level level = king.level();
        int maxRadius = 6; // 半径 6 格
        // 尝试在周围半径 maxRadius 格内找合适位置
        for (int attempt = 0; attempt < 64; attempt++) {
            double angle = random.nextDouble() * 2 * Math.PI;
            double radius = 2.0 + random.nextDouble() * (maxRadius - 2); // 2 到 maxRadius
            int dx = (int) Math.round(Math.cos(angle) * radius);
            int dz = (int) Math.round(Math.sin(angle) * radius);
            BlockPos candidate = king.blockPosition().offset(dx, 0, dz);
            BlockPos groundPos = candidate.below();
            BlockState groundState = level.getBlockState(groundPos);
            // 优先砂土、草方块、泥土等
            boolean isSuitable = groundState.is(Blocks.COARSE_DIRT) || groundState.is(Blocks.GRASS_BLOCK) || groundState.is(Blocks.DIRT);
            // 检查位置是否为空
            if (level.isEmptyBlock(candidate) && level.isEmptyBlock(candidate.above())) {
                // 检查是否被占用
                if (occupiedPositions != null && occupiedPositions.contains(candidate)) {
                    continue;
                }
                // 检查视线
                if (!hasLineOfSight(candidate)) {
                    continue;
                }
                if (isSuitable) {
                    return candidate;
                }
            }
        }
        // 降级：任意空气位置，同样检查视线和占用
        for (int attempt = 0; attempt < 64; attempt++) {
            double angle = random.nextDouble() * 2 * Math.PI;
            double radius = 2.0 + random.nextDouble() * (maxRadius - 2);
            int dx = (int) Math.round(Math.cos(angle) * radius);
            int dz = (int) Math.round(Math.sin(angle) * radius);
            BlockPos candidate = king.blockPosition().offset(dx, 0, dz);
            if (level.isEmptyBlock(candidate) && level.isEmptyBlock(candidate.above())) {
                if (occupiedPositions != null && occupiedPositions.contains(candidate)) {
                    continue;
                }
                if (hasLineOfSight(candidate)) {
                    return candidate;
                }
            }
        }
        return null;
    }

    /** 首次召唤：三种各一只 */
    private void summonAllTypesOneEach() {
        Level level = king.level();
        Scoreboard scoreboard = level.getScoreboard();
        String teamName = "skeleton_army";
        PlayerTeam team = scoreboard.getPlayerTeam(teamName);
        if (team == null) {
            team = scoreboard.addPlayerTeam(teamName);
            team.setAllowFriendlyFire(false);
        }
        if (king.getTeam() == null) {
            scoreboard.addPlayerToTeam(king.getScoreboardName(), team);
        }

        List<EntityType<? extends Mob>> allTypes = List.of(
                ModEntities.SKELETON_WARRIOR.get(),
                ModEntities.SKELETON_ARCHER.get(),
                ModEntities.SKELETON_WARLOCK.get()
        );

        List<BlockPos> usedPositions = new ArrayList<>();
        for (EntityType<? extends Mob> type : allTypes) {
            Mob mob = type.create(level);
            if (mob != null) {
                BlockPos summonPos = findValidSummonPosition(usedPositions);
                if (summonPos != null) {
                    mob.setPos(summonPos.getX() + 0.5, summonPos.getY(), summonPos.getZ() + 0.5);
                    usedPositions.add(summonPos);
                } else {
                    // 降级：国王脚下方块附近，避免重叠
                    BlockPos below = king.blockPosition().below();
                    if (level.isEmptyBlock(below) && level.isEmptyBlock(below.above())) {
                        mob.setPos(below.getX() + 0.5, below.getY(), below.getZ() + 0.5);
                        usedPositions.add(below);
                    } else {
                        mob.setPos(king.getX(), king.getY(), king.getZ());
                    }
                }
                mob.setTarget(king.getTarget());
                scoreboard.addPlayerToTeam(mob.getScoreboardName(), team);
                // 启动召唤动画
                switch (mob) {
                    case SkeletonWarriorEntity warrior -> warrior.startSummonAnimation();
                    case SkeletonArcherEntity archer -> archer.startSummonAnimation();
                    case SkeletonWarlockEntity warlock -> warlock.startSummonAnimation();
                    default -> {
                    }
                }
                level.addFreshEntity(mob);
            }
        }
    }

    /** 普通召唤：按缺失类型补全 */
    private void summonMinions() {
        Level level = king.level();
        Scoreboard scoreboard = level.getScoreboard();
        String teamName = "skeleton_army";
        PlayerTeam team = scoreboard.getPlayerTeam(teamName);
        if (team == null) {
            team = scoreboard.addPlayerTeam(teamName);
            team.setAllowFriendlyFire(false);
        }
        if (king.getTeam() == null) {
            scoreboard.addPlayerToTeam(king.getScoreboardName(), team);
        }

        int existingCount = getCurrentSummonCount();
        int maxSummons = getMaxSummons();
        int wantedCount = king.isEnraged()
                ? RemainsCaveConfig.COMMON.summonWantedCountEnraged.get()
                : RemainsCaveConfig.COMMON.summonWantedCount.get();
        int available = maxSummons - existingCount;
        int actualCount = Math.min(wantedCount, Math.max(0, available));

        double radius = RemainsCaveConfig.COMMON.summonRadius.get();
        EntityType<? extends Mob> typeToSummon = getMissingType();

        List<BlockPos> usedPositions = new ArrayList<>();
        for (int i = 0; i < actualCount; i++) {
            Mob mob = typeToSummon.create(level);
            if (mob != null) {
                BlockPos summonPos = findValidSummonPosition(usedPositions);
                if (summonPos != null) {
                    mob.setPos(summonPos.getX() + 0.5, summonPos.getY(), summonPos.getZ() + 0.5);
                    usedPositions.add(summonPos);
                } else {
                    // 降级：国王脚下方块附近
                    BlockPos below = king.blockPosition().below();
                    if (level.isEmptyBlock(below) && level.isEmptyBlock(below.above())) {
                        mob.setPos(below.getX() + 0.5, below.getY(), below.getZ() + 0.5);
                        usedPositions.add(below);
                    } else {
                        mob.setPos(king.getX(), king.getY(), king.getZ());
                    }
                }
                mob.setTarget(king.getTarget());
                scoreboard.addPlayerToTeam(mob.getScoreboardName(), team);
                // 每个实体都调用动画
                switch (mob) {
                    case SkeletonWarriorEntity warrior -> warrior.startSummonAnimation();
                    case SkeletonArcherEntity archer -> archer.startSummonAnimation();
                    case SkeletonWarlockEntity warlock -> warlock.startSummonAnimation();
                    default -> {
                    }
                }
                level.addFreshEntity(mob);
            }
        }
    }

    private EntityType<? extends Mob> getMissingType() {
        Level level = king.level();
        AABB area = king.getBoundingBox().inflate(18, 5, 18);
        List<LivingEntity> entities = level.getEntitiesOfClass(LivingEntity.class, area);

        int warriorCount = 0, archerCount = 0, warlockCount = 0;
        for (LivingEntity e : entities) {
            if (e instanceof SkeletonWarriorEntity) warriorCount++;
            else if (e instanceof SkeletonArcherEntity) archerCount++;
            else if (e instanceof SkeletonWarlockEntity) warlockCount++;
        }

        int minCount = Math.min(warriorCount, Math.min(archerCount, warlockCount));
        List<EntityType<? extends Mob>> candidates = new ArrayList<>();
        if (warriorCount == minCount) candidates.add(ModEntities.SKELETON_WARRIOR.get());
        if (archerCount == minCount) candidates.add(ModEntities.SKELETON_ARCHER.get());
        if (warlockCount == minCount) candidates.add(ModEntities.SKELETON_WARLOCK.get());

        return candidates.get(random.nextInt(candidates.size()));
    }
}