//
// Command evaluator for AI lookahead search.
// Separated from AIScoreCalculator to isolate pure state scoring from lookahead logic.
//

#ifndef EAGLE0_AICOMMANDEVALUATOR_HPP
#define EAGLE0_AICOMMANDEVALUATOR_HPP

#include <chrono>
#include <future>

#include "src/main/cpp/net/eagle0/shardok/ai/AIStrategy.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/ActionPointDistancesCache.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/CoordsSet.hpp"
#include "src/main/protobuf/net/eagle0/shardok/api/command_descriptor.pb.h"
#include "src/main/protobuf/net/eagle0/shardok/common/command_type.pb.h"

namespace shardok {

// Forward declarations
class AIScoreCalculator;
class ShardokEngine;

using ScoreValue = double;
using CommandProto = net::eagle0::shardok::api::CommandDescriptor;
using CommandType = net::eagle0::shardok::common::CommandType;
using BattalionTypeGetter = std::function<BattalionTypeSPtr(BattalionTypeId)>;

/// Evaluates commands with lookahead using minimax-style search.
/// Uses AIScoreCalculator for pure state evaluation, adds recursive lookahead logic.
class AICommandEvaluator {
public:
    /// Construct evaluator with a scorer for state evaluation and dependencies for command
    /// filtering
    AICommandEvaluator(
            const AIScoreCalculator& scorer,
            const APDCache& apdCache,
            BattalionTypeGetter battalionTypeGetter);  // Pass by value

    /// Evaluates the score for a particular command index with lookahead.
    [[nodiscard]] auto EvaluateCommand(
            PlayerId pid,
            bool isDefender,
            int remainingLookahead,
            int maxRepeatCount,
            const ShardokEngine& guessedEngine,
            const AIStrategy& attackerStrategy,
            ScoreValue currentUtility,
            const CoordsSet& allCastleCoords,
            size_t commandIndex,
            std::chrono::steady_clock::time_point deadline) const -> std::future<ScoreValue>;

    /// Find the best command among all available commands at the given depth.
    struct IndexAndScore {
        size_t index;
        CommandType type;
        ScoreValue lookaheadScore;
        ScoreValue immediateScore;
    };

    [[nodiscard]] auto FindBestCommand(
            PlayerId pid,
            bool isDefender,
            int remainingLookahead,
            int maxRepeatCount,
            const ShardokEngine& guessedEngine,
            const AIStrategy& attackerStrategy,
            ScoreValue currentUtility,
            const CoordsSet& allCastleCoords,
            std::chrono::steady_clock::time_point deadline) const -> std::future<IndexAndScore>;

private:
    const AIScoreCalculator& scorer_;
    const APDCache& apdCache_;
    BattalionTypeGetter battalionTypeGetter_;  // Store by value

    struct ImmediateAndLookaheadScore {
        ScoreValue immediateScore;
        std::future<ScoreValue> lookaheadScore;
    };

    /// Recursive lookahead calculator
    [[nodiscard]] auto PerformLookahead(
            PlayerId pid,
            bool isDefender,
            int remainingLookahead,
            int maxRepeatCount,
            const std::shared_ptr<ShardokEngine>& innerEngine,
            ScoreValue currentUtility,
            const AIStrategy& attackerStrategy,
            const CoordsSet& allCastleCoords,
            std::chrono::steady_clock::time_point deadline) const -> std::future<ScoreValue>;

    /// Evaluate single command execution with randomness handling
    [[nodiscard]] auto EvaluateWithRandomness(
            PlayerId pid,
            bool isDefender,
            uint32_t commandIndex,
            int remainingLookahead,
            int maxRepeatCount,
            const std::shared_ptr<class RandomGenerator>& randomGenerator,
            const ShardokEngine& guessedEngine,
            const AIStrategy& attackerStrategy,
            const CoordsSet& allCastleCoords,
            std::chrono::steady_clock::time_point deadline) const -> ImmediateAndLookaheadScore;
};

}  // namespace shardok

#endif  // EAGLE0_AICOMMANDEVALUATOR_HPP
