//
// Shardok-specific game state adapter implementation
//

#include "ShardokGameState.hpp"

#include <sstream>
#include <string>
#include <utility>

#include "src/main/cpp/net/eagle0/shardok/ai/AIScoreCalculator.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"

namespace shardok::mcts {

ShardokGameState::ShardokGameState(
        GameStateW state,
        const AIScoreCalculator* calculator,
        const GameSettings* settings,
        const bool isDefender,
        AIStrategy strategy,
        const CoordsSet& castleCoords,
        const APDCache& apdCache,
        const ALCache& alCache,
        const CoordsSet& criticalTileCoords)
    : state_(std::move(state)),
      scoreCalculator_(calculator),
      settings_(settings),
      isDefender_(isDefender),
      strategy_(std::move(strategy)),
      castleCoords_(castleCoords),
      apdCache_(apdCache),
      alCache_(alCache),
      criticalTileCoords_(criticalTileCoords) {}

uint64_t ShardokGameState::hash() const {
    if (!hashCached_) {
        cachedHash_ = state_.ComputeFNV1aHash();
        hashCached_ = true;
    }
    return cachedHash_;
}

double ShardokGameState::score(MCTSPlayerId /*playerId*/) const {
    return scoreCalculator_->GuessedStateScore(isDefender_, state_, strategy_, castleCoords_);
}

MCTSPlayerId ShardokGameState::currentPlayerId() const { return state_->current_player(); }

bool ShardokGameState::isTerminal() const {
    // Check if game status indicates the game is over
    if (state_->status()) {
        const auto gameStatus = state_->status()->state();
        if (gameStatus == net::eagle0::shardok::storage::fb::GameStatus_::State_VICTORY ||
            gameStatus == net::eagle0::shardok::storage::fb::GameStatus_::State_DRAW) {
            return true;
        }
    }

    // Check max rounds
    if (state_->current_round() >= settings_->GetGetter().Backing().max_rounds()) { return true; }

    return false;
}

std::unique_ptr<MCTSGameState> ShardokGameState::clone() const {
    auto cloned = std::make_unique<ShardokGameState>(
            state_,
            scoreCalculator_,
            settings_,
            isDefender_,
            strategy_,
            castleCoords_,
            apdCache_,
            alCache_,
            criticalTileCoords_);
    // Don't copy the cached engine - each state needs its own
    return cloned;
}

bool ShardokGameState::equals(const MCTSGameState& other) const {
    const auto* shardokOther = dynamic_cast<const ShardokGameState*>(&other);
    if (!shardokOther) { return false; }

    return hash() == shardokOther->hash();
}

MCTSPlayerId ShardokGameState::getWinner() const {
    // Note: FlatBuffer doesn't have a winner field
    // In practice, this would need to determine winner from victory conditions
    return -1;  // No winner
}

std::string ShardokGameState::toString() const {
    std::stringstream ss;
    ss << "ShardokGameState[Round:" << static_cast<int>(state_->current_round())
       << " Player:" << currentPlayerId() << " Hash:" << hash() << "]";
    return ss.str();
}

}  // namespace shardok::mcts
