//
// Created by Dan Crosby on 8/30/23.
//

#include "AIDefenderStrategySelector.hpp"

#include "src/main/cpp/net/eagle0/shardok/ai/AIScoreUtilities.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AIWaterCrossingCalculator.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"

namespace shardok {

constexpr double MAXIMUM_RATIO_FOR_DEFENDER_TO_FLEE = 0.15;
constexpr double MINIMUM_RATIO_FOR_DEFENDER_TO_HOLD = 0.60;

auto AIDefenderStrategySelector::BestDefenderStrategy(
        const GameState* gameState,
        const CoordsSet& criticalTileCoords,
        const APDCache& apdCache,
        const SettingsGetter& settings) -> AIStrategy {
    uint32_t attackerNonUndeadUnitCount = 0;
    uint32_t attackerNonUndeadUnitNotRequiringWaterCrossingCount = 0;
    int attackerTroops = 0;
    int defenderTroops = 0;

    bool canFlee = false;

    vector<UnitId> attackerUnitIdsRequiringWaterCrossing{};
    for (const auto& player : *gameState->player_infos()) {
        if (!player->is_defender()) {
            const auto& unitIdsRequiringWaterCrossing = UnitIdsRequiringWaterCrossing(
                    gameState,
                    player->player_id(),
                    criticalTileCoords,
                    apdCache,
                    settings);
            attackerUnitIdsRequiringWaterCrossing.insert(
                    attackerUnitIdsRequiringWaterCrossing.end(),
                    unitIdsRequiringWaterCrossing.begin(),
                    unitIdsRequiringWaterCrossing.end());
        }
    }

    for (const Unit* unit : *gameState->units()) {
        if (unit->status() != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT &&
            unit->status() != net::eagle0::shardok::storage::fb::UnitStatus_RESERVE_UNIT)
            continue;

        const auto* pi = PlayerInfoForPid(gameState, unit->player_id());

        if (pi != nullptr) {
            if (pi->is_defender()) {
                defenderTroops += unit->battalion().size();
                if (unit->can_flee()) canFlee = true;
            } else {
                if (unit->battalion().type() !=
                    net::eagle0::shardok::storage::fb::BattalionTypeId_UNDEAD) {
                    ++attackerNonUndeadUnitCount;

                    if (!common::Contains(attackerUnitIdsRequiringWaterCrossing, unit->unit_id())) {
                        ++attackerNonUndeadUnitNotRequiringWaterCrossingCount;
                    }
                }
                attackerTroops += unit->battalion().size();
            }
        }
    }

    const int roundsRemaining = 32 - gameState->current_round();
    AIStrategy chosenStrategy;

    // Defender will flee if
    //  * they can
    //  * there are more than two rounds remaining
    //  * the attacker has enough units that do not require crossing riviers to take all the castles
    //  * the defender has way, way fewer troops
    // other considerations we should have but do not presently:
    //  * the attacker is close to the defender / castles
    if (canFlee && roundsRemaining > 2 &&
        defenderTroops < MAXIMUM_RATIO_FOR_DEFENDER_TO_FLEE * attackerTroops &&
        attackerNonUndeadUnitNotRequiringWaterCrossingCount >= criticalTileCoords.size()) {
        chosenStrategy = FleeStrategy;
    } else if (attackerNonUndeadUnitCount >= criticalTileCoords.size()) {
        chosenStrategy = HoldCastlesStrategy;
    } else if (defenderTroops > MINIMUM_RATIO_FOR_DEFENDER_TO_HOLD * attackerTroops) {
        chosenStrategy = HoldCastlesStrategy;
    } else {
        chosenStrategy = ScatterStrategy;
    }

    return chosenStrategy;
}
}  // namespace shardok
