//
//  ShardokAIClient.hpp
//  eagle0
//
//  Created by Dan Crosby on 10/18/17.
//  Copyright © 2017 none. All rights reserved.
//

#ifndef ShardokAIClient_hpp
#define ShardokAIClient_hpp

#include <vector>

#include "src/main/cpp/net/eagle0/common/RandomGenerator.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AIScoreCalculator.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AITimeBudget.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AIWaterCrossingCommandChooser.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/IterativeDeepeningAI.hpp"
#include "src/main/protobuf/net/eagle0/shardok/api/game_state_view.pb.h"

namespace shardok {

using VictoryCondition = net::eagle0::shardok::storage::fb::VictoryCondition;

/// Results from AI command selection, including performance metrics.
struct CommandChoiceResults {
    size_t chosenIndex;            ///< Index of the chosen command in the available commands list
    size_t availableCommandCount;  ///< Total number of commands that were available to choose from
    int depthAchieved;             ///< Maximum search depth reached for the best command
    size_t commandCountEvaluated;  ///< Number of commands evaluated at the highest achieved depth
    EvaluationCompletionReason completionReason;  ///< Why evaluation stopped at this depth
};

//
//  A ShardokGameClient representing an AI player.
//
class ShardokAIClient {
private:
    const PlayerId playerId;
    const bool isDefender;

    APDCache apdCache = std::make_shared<ActionPointDistancesCache>();
    ALCache alCache;

    const AIWaterCrossingCommandChooser waterCrossingCommandChooser;

    [[nodiscard]] auto StandardChooseCommandIndex(
            const GameSettingsSPtr& settings,
            const GameStateW& guessedState,
            const vector<CommandProto>& realAvailableCommands) const -> CommandChoiceResults;
    [[nodiscard]] auto LateRoundAttackerChooseCommandIndex(
            const GameSettingsSPtr& settings,
            const GameStateW& guessedState,
            const vector<CommandProto>& realAvailableCommands) const -> CommandChoiceResults;
    [[nodiscard]] auto FinalRoundAttackerChooseCommandIndex(
            const GameSettingsSPtr& settings,
            const GameStateW& guessedState,
            const vector<CommandProto>& realAvailableCommands) const -> CommandChoiceResults;

    [[nodiscard]] auto ChooseCommandIndex(
            const GameSettingsSPtr& settings,
            const net::eagle0::shardok::api::GameStateView& gsv,
            const vector<CommandProto>& realAvailableCommands) const -> CommandChoiceResults;

public:
    explicit ShardokAIClient(
            PlayerId playerId,
            bool isDefender,
            const HexMap* hexMap,
            const SettingsGetter& settings);
    ~ShardokAIClient() = default;

    [[nodiscard]] auto GetPlayerId() const -> PlayerId { return playerId; }

    [[nodiscard]] auto ChooseCommandIndex(const ShardokEngine& engine) const
            -> CommandChoiceResults;
};
}  // namespace shardok

#endif /* ShardokAIClient_hpp */
