#include "SalvageScrapEvaluator.h"

#include <optional>
#include <unordered_map>
#include <vector>

#include <QVector2D>

#include "BehaviorScores.h"
#include "BehaviorTargeting.h"
#include "EntityAdmin.h"
#include "PositionComponent.h"
#include "SalvageScrapBehavior.h"
#include "DebrisSystem.h"
#include "SensorRangeComponent.h"
#include "tracing.h"

void SalvageScrapEvaluator::evaluate(EntityAdmin& admin)
{
    TRACE();
    const std::unordered_map<entt::entity, CargoState> cargoByShip = buildCargoByShip(admin);
    const std::vector<DebrisInfo> allDebris = getAllDebrisInfo(admin);

    admin.forEach<SalvageScrapBehavior, PositionComponent, SensorRangeComponent>(
        [&](entt::entity e, SalvageScrapBehavior& salvage, const PositionComponent& pos,
            const SensorRangeComponent& sensor)
        {
            const std::unordered_map<entt::entity, CargoState>::const_iterator it =
                cargoByShip.find(e);
            const bool cargoFull = (it != cargoByShip.end()) && isCargoFull(it->second);

            if (cargoFull)
            {
                salvage.debrisTarget = std::nullopt;
                salvage.score = BehaviorScores::kInactive;
                return;
            }

            // Find nearest debris within sensor range.
            float bestDist = sensor.value_tiles;
            std::optional<QVector2D> bestPos;
            for (const DebrisInfo& si : allDebris)
            {
                const float dist = (si.position - pos.value).length();
                if (dist < bestDist)
                {
                    bestDist = dist;
                    bestPos  = si.position;
                }
            }

            salvage.debrisTarget = bestPos;
            salvage.score = bestPos ? BehaviorScores::kSalvage : BehaviorScores::kInactive;
        });
}
