//
//  AIFleeDecisionCalculator.cpp
//  eagle0
//
//  Handles AI flee decision logic including combat success estimation
//  and flee vs fight evaluation for final round scenarios
//

#include "AIFleeDecisionCalculator.hpp"

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

namespace shardok {

auto AIFleeDecisionCalculator::GetFleeCommandIndex(
        const vector<CommandProto>::const_iterator& fleeCommand,
        const vector<CommandProto>& availableCommands) -> size_t {
    return static_cast<size_t>(std::distance(availableCommands.begin(), fleeCommand));
}

auto AIFleeDecisionCalculator::EstimateCombatSuccess(
        PlayerId attackerPlayerId,
        const GameStateW& guessedState,
        const GameSettingsSPtr& settings) -> double {
    // Combat success estimation based on troops, heroes, and capture dynamics

    int attackerTroops = 0;
    int defenderTroops = 0;
    int attackerUnits = 0;
    int defenderUnits = 0;
    int attackerHeroes = 0;
    int defenderHeroes = 0;
    bool defenderHasVips = false;

    // Count troops, units, and heroes for each side
    for (const auto* unit : *guessedState->units()) {
        if (unit->status() != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT) continue;

        const auto* pi = PlayerInfoForPid(guessedState, unit->player_id());
        if (pi == nullptr) continue;

        const int unitTroops = unit->battalion().size();
        const bool hasHero = unit->has_attached_hero();

        if (pi->is_defender()) {
            defenderTroops += unitTroops;
            defenderUnits++;
            if (hasHero) {
                defenderHeroes++;
                if (unit->attached_hero().is_vip()) { defenderHasVips = true; }
            }
        } else if (unit->player_id() == attackerPlayerId) {
            attackerTroops += unitTroops;
            attackerUnits++;
            if (hasHero) { attackerHeroes++; }
        }
    }

    const int roundsRemaining =
            settings->GetGetter().Backing().max_rounds() - guessedState->current_round();

    // Special case: Attacker has no troops
    if (attackerTroops == 0) {
        // Even with heroes, attacker is extremely unlikely to win without troops
        return 0.01;  // Near zero, but not absolute zero
    }

    // Special case: Defender has no troops but has heroes
    if (defenderTroops == 0 && defenderHeroes > 0) {
        // Defender can win by running out the clock if attacker can't capture heroes
        // Success depends heavily on remaining time and attacker's ability to capture
        if (roundsRemaining <= 3) {
            // Very hard for attacker to capture all heroes in time
            return 0.15;  // Low chance
        } else if (roundsRemaining <= 5) {
            return 0.25;  // Still difficult
        } else {
            // More time available, but still challenging
            return 0.35;
        }
    }

    // Special case: Defender has neither troops nor heroes
    if (defenderTroops == 0 && defenderHeroes == 0) {
        return 0.95;  // Nearly guaranteed win
    }

    // Normal case: Both sides have troops
    // Base probability from troop ratio
    const double troopRatio =
            static_cast<double>(attackerTroops) / static_cast<double>(defenderTroops);
    double baseProbability = std::min(0.95, std::max(0.05, troopRatio * 0.5));

    // Adjust for time pressure - attackers need to win before time runs out
    if (roundsRemaining <= 1) {
        baseProbability *= 0.6;  // Severe penalty for last round
    } else if (roundsRemaining <= 3) {
        baseProbability *= 0.8;  // Moderate penalty
    }

    // Adjust for unit count (more units = better tactical flexibility)
    const double unitRatio =
            static_cast<double>(attackerUnits) / std::max(1.0, static_cast<double>(defenderUnits));
    if (unitRatio < 0.5) {
        baseProbability *= 0.8;
    } else if (unitRatio > 1.5) {
        baseProbability *= 1.15;
    }

    // Adjust for hero presence
    if (defenderHeroes > attackerHeroes && defenderHasVips) {
        // Defender has more heroes including VIPs - harder to capture
        baseProbability *= 0.85;
    }

    return std::min(0.95, std::max(0.05, baseProbability));
}

auto AIFleeDecisionCalculator::EvaluateFleeVsFight(
        PlayerId playerId,
        const GameSettingsSPtr& settings,
        const GameStateW& guessedState,
        const vector<CommandProto>& availableCommands,
        const vector<CommandProto>::const_iterator& fleeCommand,
        bool enableDebugLogging) -> FleeDecision {
    // Get flee success odds
    const int fleeSuccessChance = fleeCommand->odds().success_chance();

    // Get thresholds from settings
    const auto settingsGetter = settings->GetGetter();
    const int minimumFleeOddsThreshold = settingsGetter.Backing().ai_minimum_flee_odds_threshold();
    const int desperateFleeThreshold = settingsGetter.Backing().ai_desperate_flee_threshold();

    if (enableDebugLogging) {
        printf("AI FinalRound: Evaluating flee (odds=%d%%)...\n", fleeSuccessChance);
    }

    // Check if flee odds are good enough to attempt
    if (fleeSuccessChance >= minimumFleeOddsThreshold) {
        if (enableDebugLogging) {
            printf("AI FinalRound: Good flee odds (%d%% >= %d%%), choosing flee\n",
                   fleeSuccessChance,
                   minimumFleeOddsThreshold);
        }
        return FleeDecision{
                true,
                GetFleeCommandIndex(fleeCommand, availableCommands),
                "Good flee odds"};
    }

    // Low flee odds - evaluate if fighting might be better
    const double combatWinChance = EstimateCombatSuccess(playerId, guessedState, settings);

    // If combat situation is hopeless, even bad flee odds are better than certain death
    if (combatWinChance < 0.05 && fleeSuccessChance >= desperateFleeThreshold) {
        if (enableDebugLogging) {
            printf("AI FinalRound: Combat hopeless (%.1f%%), desperate flee attempt (%d%%)\n",
                   combatWinChance * 100,
                   fleeSuccessChance);
        }
        return FleeDecision{
                true,
                GetFleeCommandIndex(fleeCommand, availableCommands),
                "Combat hopeless, desperate flee"};
    }

    // Detailed flee vs fight comparison
    const double fleeChance = static_cast<double>(fleeSuccessChance) / 100.0;

    // Compare expected outcomes:
    // - Flee: fleeChance of survival (not victory, but avoiding loss)
    // - Fight: combatWinChance of victory (better than survival)

    constexpr double FLEE_VS_COMBAT_MARGIN =
            0.8;  // Require 80% of combat chance to prefer fighting
    const double adjustedCombatThreshold = combatWinChance * FLEE_VS_COMBAT_MARGIN;

    if (enableDebugLogging) {
        printf("AI FinalRound: Flee=%d%%, Combat=%.1f%%, Threshold=%.1f%% -> ",
               fleeSuccessChance,
               combatWinChance * 100,
               adjustedCombatThreshold * 100);
    }

    if (fleeChance > adjustedCombatThreshold) {
        if (enableDebugLogging) { printf("FLEE (better odds)\n"); }
        return FleeDecision{
                true,
                GetFleeCommandIndex(fleeCommand, availableCommands),
                "Flee has better expected outcome"};
    } else {
        if (enableDebugLogging) { printf("FIGHT (better expected outcome)\n"); }
        // Return 0 to indicate we should use standard command selection
        return FleeDecision{
                false,
                0,  // Will be replaced by StandardChooseCommandIndex
                "Fighting has better expected outcome"};
    }
}

}  // namespace shardok
