//
// Created by Dan Crosby on 07/04/25.
//

#include "AITimeBudget.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/FlatbufferWrapper.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexCubeUtils.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/game_state.hpp"

namespace shardok {

// Static member definition
std::atomic<int> AIEvaluationCounter::activeCount{0};

AIEvaluationCounter::AIEvaluationCounter() { activeCount++; }

AIEvaluationCounter::~AIEvaluationCounter() { activeCount--; }

int AIEvaluationCounter::GetCurrentCount() { return activeCount.load(); }

auto CalculateTimeBudget(
        const PlayerId playerId,
        const GameSettingsSPtr &settings,
        const GameStateW &state) -> AITimeBudget {
    const auto settingsGetter = settings->GetGetter();
    const auto castleCoords = AllCastleCoords(state->hex_map());

    // Determine proximity (≤4 hex distance) - applies to both attackers and defenders
    bool isClose = false;
    const auto *units = state->units();

    for (int i = 0; i < units->size() && !isClose; ++i) {
        const auto *myUnit = units->Get(i);
        if (myUnit->player_id() != playerId) continue;

        const auto &myCoords = myUnit->location();
        // Skip units that haven't been placed on the map yet
        if (myCoords.row() == -1) continue;

        const Cube myCube = OffsetToCube(myCoords);

        // Check distance to enemy units
        for (int j = 0; j < units->size(); ++j) {
            const auto *enemyUnit = units->Get(j);
            if (enemyUnit->player_id() == playerId) continue;

            const auto &enemyCoords = enemyUnit->location();
            // Skip enemy units that haven't been placed on the map yet
            if (enemyCoords.row() == -1) continue;

            const Cube enemyCube = OffsetToCube(enemyCoords);

            if (const int hexDistance = CubeDistance(myCube, enemyCube); hexDistance <= 4) {
                isClose = true;
                break;
            }
        }

        // Check distance to castles
        if (!isClose) {
            for (const auto &castleCoord : castleCoords) {
                const Cube castleCube = OffsetToCube(castleCoord);

                if (const int hexDistance = CubeDistance(myCube, castleCube); hexDistance <= 4) {
                    isClose = true;
                    break;
                }
            }
        }
    }

    // Get time budget from settings
    const auto budget = std::chrono::duration<double>(
            isClose ? settingsGetter.Backing().lookahead_time_budget_close_in_seconds()
                    : settingsGetter.Backing().lookahead_time_budget_far_in_seconds());

    const auto remainingBudget = std::chrono::duration_cast<std::chrono::milliseconds>(budget);

    // Get minimum depth requirement
    const int minDepth = settingsGetter.Backing().min_lookahead_turns();

    return AITimeBudget{
            .remainingBudget = remainingBudget,
            .minDepthRequired = minDepth,
            .isCloseToEnemy = isClose};
}

}  // namespace shardok