#include "RepairEvaluator.h"

#include <vector>

#include "BehaviorScores.h"
#include "BehaviorTargeting.h"
#include "EntityAdmin.h"
#include "FactionComponent.h"
#include "HealthComponent.h"
#include "PositionComponent.h"
#include "RepairBehavior.h"
#include "SensorRangeComponent.h"
#include "tracing.h"

void RepairEvaluator::evaluate(EntityAdmin& admin)
{
    TRACE();
    const std::vector<RepairableInfo> repairables = buildRepairables(admin);

    admin.forEach<RepairBehavior, PositionComponent, SensorRangeComponent, FactionComponent>(
        [&](entt::entity e, RepairBehavior& repair, const PositionComponent& pos,
            const SensorRangeComponent& sensor, const FactionComponent& faction)
        {
            // Validate current target: same faction, alive and still damaged.
            bool targetValid = false;
            if (repair.currentTarget)
            {
                const entt::entity t = *repair.currentTarget;
                if (admin.isValid(t) && admin.hasAll<HealthComponent, FactionComponent>(t))
                {
                    const HealthComponent&  th = admin.get<HealthComponent>(t);
                    const FactionComponent& tf = admin.get<FactionComponent>(t);
                    if (tf.isEnemy == faction.isEnemy && th.hp > 0.0f && th.hp < th.maxHp)
                    {
                        targetValid = true;
                    }
                }
            }

            // Acquire nearest damaged friendly within sensor range. Friendly is
            // relative to this ship's faction, not the absolute isEnemy flag.
            if (!targetValid)
            {
                repair.currentTarget = std::nullopt;
                float bestDist = sensor.value_tiles;
                for (const RepairableInfo& r : repairables)
                {
                    if (r.entity == e) { continue; }
                    if (r.isEnemy != faction.isEnemy) { continue; }
                    if (r.hp <= 0.0f || r.hp >= r.maxHp) { continue; }
                    const float dist = (r.position - pos.value).length();
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        repair.currentTarget = r.entity;
                    }
                }
            }

            repair.score = repair.currentTarget
                ? BehaviorScores::kRepair
                : BehaviorScores::kInactive;
        });
}
