//
// Shardok-specific MCTS AI implementation using abstract interfaces
//

#include "ShardokMCTSAI.hpp"

#include "adapters/ShardokGameEngine.hpp"
#include "adapters/ShardokGameState.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AICommandFilter.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AIScoreCalculator.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/ShardokEngine.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"

namespace shardok {

ShardokMCTSAI::ShardokMCTSAI(
        PlayerId playerId,
        bool isDefender,
        AIStrategy strategy,
        const CoordsSet& castleCoords,
        const AIScoreCalculator& scoreCalculator,
        const APDCache& apdCache,
        const ALCache& alCache,
        MCTSConfig config)
    : abstractAI_(std::make_unique<mcts::AbstractMCTSAI>(
              static_cast<mcts::MCTSPlayerId>(playerId),
              config)),
      playerId_(playerId),
      isDefender_(isDefender),
      strategy_(strategy),
      castleCoords_(castleCoords),
      scoreCalculator_(scoreCalculator),
      apdCache_(apdCache),
      alCache_(alCache) {}

auto ShardokMCTSAI::Search(
        const GameSettingsSPtr& settings,
        const GameStateW& state,
        const AITimeBudget& budget) const -> SearchResult {
    // Compute critical tiles once to avoid 8.5% runtime overhead in ShardokEngine construction
    const auto criticalTiles = GetCriticalTileLocations(state->hex_map());

    // Create Shardok engine for simulation
    ShardokEngine engine(settings, state, criticalTiles, 0, false);

    // Create game state adapter
    auto gameState = mcts::ShardokMCTSFactory::createGameState(
            state,
            &scoreCalculator_,  // Pass the score calculator
            settings,           // Pass shared_ptr directly
            isDefender_,
            strategy_,
            castleCoords_,
            apdCache_,
            alCache_,
            criticalTiles);

    // Create game engine adapter (passing critical tiles to avoid recomputation)
    auto gameEngine = mcts::ShardokMCTSFactory::createGameEngine(
            engine,
            nullptr,            // commandFilter - simplified
            &scoreCalculator_,  // Pass the score calculator
            settings,
            apdCache_,
            alCache_,
            playerId_,
            isDefender_,
            strategy_,
            castleCoords_,
            criticalTiles);

    // Perform abstract search
    const auto timeLimit = budget.remainingBudget;
    const auto abstractResult = abstractAI_->Search(*gameEngine, *gameState, timeLimit);

    // Get unfiltered command count for consistent reporting with IterativeDeepeningAI
    // (MCTS uses filtered commands internally, but we report unfiltered count for metrics)
    const auto unfilteredCommands = engine.GetAvailableCommandsForAIPlayer(
            static_cast<PlayerId>(gameState->currentPlayerId()));
    const size_t unfilteredCount = unfilteredCommands ? unfilteredCommands->size() : 0;

    // Convert result back to Shardok format
    SearchResult result;
    // Map filtered index back to original unfiltered index
    result.bestCommandIndex =
            gameEngine->mapFilteredIndexToOriginal(abstractResult.bestActionIndex, *gameState);
    result.bestScore = abstractResult.bestScore;
    result.depthAchieved = static_cast<size_t>(abstractResult.searchDepth);
    result.commandCountEvaluated = static_cast<size_t>(abstractResult.nodesEvaluated);
    result.timeUsed = abstractResult.searchTime;
    result.availableCommandCount = unfilteredCount;
    result.minimumDepthCompleted =
            (abstractResult.searchDepth >= static_cast<int>(budget.minDepthRequired));
    result.searchCompleted = true;  // MCTS is anytime - always returns a valid result

    // Determine completion reason based on what actually happened
    if (abstractResult.foundWinningMove || unfilteredCount == 0) {
        // Found a terminal winning state or no commands available
        result.completionReason = EvaluationCompletionReason::RAN_OUT_OF_COMMANDS;
    } else {
        // Normal case - time budget exhausted while exploring
        result.completionReason = EvaluationCompletionReason::RAN_OUT_OF_TIME;
    }

    return result;
}

}  // namespace shardok