//
//  TutorialBattleController.hpp
//  eagle0
//
//  Created for tutorial battle system.
//  Copyright 2025 none. All rights reserved.
//

#ifndef TutorialBattleController_hpp
#define TutorialBattleController_hpp

#include <optional>
#include <set>
#include <string>
#include <vector>

#include "src/main/cpp/net/eagle0/common/RandomGenerator.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/Coordinates.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"
#include "src/main/protobuf/net/eagle0/common/tutorial_battle_config.pb.h"
#include "src/main/protobuf/net/eagle0/shardok/storage/action_result.pb.h"

namespace shardok {

using ActionResult = net::eagle0::shardok::storage::ActionResult;
using TutorialBattleConfigProto = net::eagle0::common::TutorialBattleConfig;
using TutorialEventProto = net::eagle0::common::TutorialEvent;
using TutorialTriggerProto = net::eagle0::common::TutorialTrigger;
using TutorialActionProto = net::eagle0::common::TutorialAction;

/// Info about a pending reinforcement placement phase.
struct ReinforcementPlacementInfo {
    PlayerId playerId;
    std::vector<Coords> startingPositions;
};

/// Results from tutorial event processing, including action results and any pending
/// reinforcement placement.
struct TutorialEventResults {
    std::vector<ActionResult> actionResults;
    std::optional<ReinforcementPlacementInfo> reinforcementPlacement;
};

/// Controller for scripted tutorial battles with event-driven triggers and actions.
/// Events are checked at the end of each round and fire in config order.
/// Each event fires at most once (tracked by event_id).
class TutorialBattleController {
public:
    /// Creates a disabled controller.
    TutorialBattleController();

    /// Creates a controller from proto configuration.
    explicit TutorialBattleController(const TutorialBattleConfigProto& protoConfig);

    /// Returns true if the controller is enabled for this battle.
    [[nodiscard]] auto IsEnabled() const -> bool { return enabled_; }

    /// Check all events at end of round, return actions for triggered events.
    /// Events fire in config order - first triggered event executes, then next.
    /// Each event fires at most once.
    [[nodiscard]] auto CheckAndExecuteEvents(
            const GameStateW& state,
            const SettingsGetter& settings,
            const std::shared_ptr<RandomGenerator>& randomGenerator) -> TutorialEventResults;

    /// Gets the set of fired event IDs (for testing/debugging).
    [[nodiscard]] auto GetFiredEventIds() const -> const std::set<std::string>& {
        return firedEventIds_;
    }

private:
    bool enabled_ = false;
    TutorialBattleConfigProto config_;
    std::set<std::string> firedEventIds_;  // Track which events have fired

    /// Evaluates whether a trigger condition is met.
    [[nodiscard]] auto EvaluateTrigger(const TutorialTriggerProto& trigger, const GameStateW& state)
            const -> bool;

    /// Executes an action and returns the resulting action results.
    [[nodiscard]] auto ExecuteAction(
            const TutorialActionProto& action,
            const GameStateW& state,
            const SettingsGetter& settings,
            const std::shared_ptr<RandomGenerator>& randomGenerator) const -> TutorialEventResults;

    // Helper methods for trigger evaluation

    /// Counts units lost (destroyed, captured, fled, retreated) for a player.
    [[nodiscard]] auto CountLostUnits(const GameStateW& state, PlayerId playerId) const -> int;

    /// Gets total damage taken (cumulative size reduction) for a player.
    [[nodiscard]] auto GetTotalDamageTaken(const GameStateW& state, PlayerId playerId) const -> int;

    /// Checks if a specific unit has been killed.
    [[nodiscard]] auto IsUnitKilled(
            const GameStateW& state,
            const net::eagle0::common::UnitKilledTrigger& trigger) const -> bool;

    // Helper methods for action execution

    /// Executes a flee action for specified units.
    [[nodiscard]] auto ExecuteFleeAction(
            const net::eagle0::common::FleeAction& fleeAction,
            const GameStateW& state) const -> std::vector<ActionResult>;

    /// Executes a reinforcements action, placing units directly at available starting positions.
    [[nodiscard]] auto ExecuteReinforcementsAction(
            const net::eagle0::common::ReinforcementsAction& reinforcementsAction,
            const GameStateW& state) const -> TutorialEventResults;
};

}  // namespace shardok

#endif /* TutorialBattleController_hpp */
