//
//  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/ai/AIUnitScoreCalculator.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"

namespace shardok {

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

auto AIFleeDecisionCalculator::EstimateCombatSuccess(
        PlayerId attackerPlayerId,
        const GameStateW& gameState,
        int maxRounds) -> double {
    if (gameState->status() == nullptr ||
        gameState->status()->state() !=
                net::eagle0::shardok::storage::fb::GameStatus_::State_GAME_RUNNING) {
        return 1.0;  // we're still in set_up so we can't really evaluate
    }

    // Combat success estimation based on unit power, heroes, and capture dynamics
    double attackerPower = 0.0;
    double defenderPower = 0.0;
    int attackerTroops = 0;  // Still track raw troops for special cases
    int defenderTroops = 0;
    int attackerUnits = 0;
    int defenderUnits = 0;
    int attackerHeroes = 0;
    int defenderHeroes = 0;
    bool defenderHasVips = false;

    // Calculate total power and count units/heroes for each side
    for (const auto* unit : *gameState->units()) {
        if (unit->status() != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT) continue;

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

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

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

    const int roundsRemaining = maxRounds - gameState->current_round();

    // Special case: Attacker has no heroes - automatic loss
    if (attackerHeroes == 0) {
        return 0.0;  // Cannot win without heroes
    }

    // Special case: Defender has no heroes - automatic win for attacker
    if (defenderHeroes == 0) {
        return 1.0;  // Guaranteed win
    }

    // Special case: Attacker has no troops (but has heroes)
    if (attackerTroops == 0) {
        // Very difficult to win with heroes alone
        return 0.05;  // Extremely low chance
    }

    // Special case: Defender has no troops but has heroes
    if (defenderTroops == 0) {
        // Defenders with only heroes are vulnerable to capture
        // Only truly difficult if time is extremely limited
        if (roundsRemaining <= 1) {
            // Last round - very hard to capture all heroes
            return 0.3;  // Low but not impossible
        } else if (roundsRemaining <= 2) {
            return 0.6;  // Still achievable
        } else {
            // With 3+ rounds, capturing defenseless heroes is quite feasible
            return 0.85;  // High probability of success
        }
    }

    // Normal case: Both sides have troops
    // Base probability from power ratio (accounts for unit quality, not just quantity)
    const double powerRatio = attackerPower / std::max(1.0, defenderPower);
    double baseProbability = std::min(0.95, std::max(0.05, powerRatio * 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 GameStateW& guessedState,
        const CommandListSPtr& availableCommands,
        const CommandList::const_iterator& fleeCommand,
        int maxRounds,
        int minimumFleeOddsThreshold,
        int desperateFleeThreshold,
        bool enableDebugLogging) -> FleeDecision {
    // Get flee success odds
    const int fleeSuccessChance = (*fleeCommand)->GetOddsPercentile();

    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, maxRounds);

    // 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"};
    }
}

auto AIFleeDecisionCalculator::ShouldConsiderFleeing(
        PlayerId attackerPlayerId,
        const GameStateW& guessedState,
        int maxRounds,
        double fleeConsiderationThreshold) -> bool {
    // Get combat success probability
    const double combatSuccessChance =
            EstimateCombatSuccess(attackerPlayerId, guessedState, maxRounds);

    // Consider fleeing if combat success chance is below threshold
    return combatSuccessChance < fleeConsiderationThreshold;
}

}  // namespace shardok
