//
// StateRecorder - Records game states during self-play for ML training
//

#ifndef EAGLE0_STATE_RECORDER_HPP
#define EAGLE0_STATE_RECORDER_HPP

#include <cstdint>
#include <string>
#include <vector>

#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-redundant-constexpr-static-def"
#include "src/main/protobuf/net/eagle0/shardok/api/game_state_view.pb.h"
#pragma clang diagnostic pop

namespace shardok {
namespace ml {

/**
 * @brief Records game state views during self-play games for ML training data collection.
 *
 * Usage:
 *   StateRecorder recorder;
 *   while (!game.IsTerminal()) {
 *     AI makes move...
 *     recorder.RecordStateView(engine.GetGameStateView(currentPlayer), currentPlayer);
 *   }
 *   recorder.SetGameOutcome(winner);
 *   recorder.WriteToFile("game_0001.bin");
 */
class StateRecorder {
public:
    /**
     * @brief A single recorded state with metadata
     */
    struct StateRecord {
        // Serialized protobuf GameStateView (player's partial information)
        std::vector<uint8_t> serializedStateView;

        // Which player's perspective this is
        PlayerId currentPlayer;

        // Which round this state occurred in
        int roundNumber;

        // Label: Did the current player win? (filled in after game ends)
        bool currentPlayerWon;

        StateRecord(std::vector<uint8_t> stateView, PlayerId player, int round)
            : serializedStateView(std::move(stateView)),
              currentPlayer(player),
              roundNumber(round),
              currentPlayerWon(false) {}
    };

    StateRecorder() = default;

    /**
     * @brief Record a game state from the current player's perspective.
     *
     * This should be called AFTER each action is applied (except END_TURN).
     * Records the resulting position that the player reached.
     *
     * @param view The GameStateView from the current player's perspective
     * @param currentPlayer The player ID whose turn it is
     */
    void RecordStateView(
            const net::eagle0::shardok::api::GameStateView& view,
            PlayerId currentPlayer);

    /**
     * @brief Set the game outcome and label all recorded states.
     *
     * @param winner The player ID who won (-1 for draw)
     */
    void SetGameOutcome(PlayerId winner);

    /**
     * @brief Write all recorded states to a binary file.
     *
     * File format:
     *   [uint32_t num_records]
     *   For each record:
     *     [uint32_t view_size]
     *     [uint8_t[] serialized_view]
     *     [int8_t current_player]
     *     [int32_t round_number]
     *     [bool current_player_won]
     *
     * @param filename Path to output file
     */
    void WriteToFile(const std::string& filename) const;

    /**
     * @brief Get the number of states recorded.
     */
    [[nodiscard]] size_t GetRecordCount() const { return states_.size(); }

    /**
     * @brief Clear all recorded states.
     */
    void Clear() {
        states_.clear();
        winner_ = -1;
    }

private:
    std::vector<StateRecord> states_;
    PlayerId winner_ = -1;  // -1 means not set yet
};

}  // namespace ml
}  // namespace shardok

#endif  // EAGLE0_STATE_RECORDER_HPP
