//
// TranspositionTable.hpp - Cache for game state evaluations to avoid redundant calculations
//

#ifndef EAGLE0_SHARDOK_AI_TRANSPOSITION_TABLE_HPP
#define EAGLE0_SHARDOK_AI_TRANSPOSITION_TABLE_HPP

#include <atomic>
#include <cstdint>
#include <optional>
#include <ostream>
#include <vector>

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

namespace shardok {

using ScoreValue = double;
// PlayerId already defined in ShardokCTypes.h

class TranspositionTable {
public:
    // Statistics for monitoring effectiveness
    struct Stats {
        std::atomic<uint64_t> probes{0};
        std::atomic<uint64_t> hits{0};
        std::atomic<uint64_t> stores{0};
        std::atomic<uint64_t> collisions{0};

        [[nodiscard]] auto hitRate() const -> double {
            const uint64_t p = probes.load();
            return p > 0 ? (100.0 * hits.load() / p) : 0.0;
        }

        void reset() {
            probes = 0;
            hits = 0;
            stores = 0;
            collisions = 0;
        }
    };

private:
    // Compact entry structure (actual size is greater than 16 bytes due to atomics and alignment)
    struct TTEntry {
        std::atomic<uint64_t> hash_full;  // Full hash for validation
        std::atomic<float> score;         // Score as float to save space
        std::atomic<uint8_t> depth;       // Search depth (0-255)
        std::atomic<uint8_t> player_id;   // Player who is to move
        std::atomic<uint16_t> age;        // For replacement strategy
    };

    static constexpr size_t TABLE_SIZE_BITS = 22;                  // 2^22 entries
    static constexpr size_t TABLE_SIZE = 1ULL << TABLE_SIZE_BITS;  // 4M entries = 64MB
    static constexpr size_t INDEX_MASK = TABLE_SIZE - 1;

    std::vector<TTEntry> table;
    Stats stats;
    std::atomic<uint16_t> current_age{0};

    // Hash function for FlatBuffer game state
    [[nodiscard]] auto hashGameState(const GameStateW& state) const -> uint64_t;

public:
    TranspositionTable();

    // Probe the table for a cached evaluation
    std::optional<ScoreValue> probe(const GameStateW& state, int depth, PlayerId player);

    // Store an evaluation in the table
    void store(const GameStateW& state, int depth, PlayerId player, ScoreValue score);

    // Clear the entire table
    void clear();

    // Increment age for replacement strategy (call at start of each search)
    void incrementAge() { current_age++; }

    // Get statistics
    [[nodiscard]] auto getStats() const -> const Stats& { return stats; }

    // Print statistics to stdout
    void printStats() const;
    void printStats(std::ostream& output) const;
};

// Global instance for the AI to use
extern TranspositionTable g_transpositionTable;

}  // namespace shardok

#endif  // EAGLE0_SHARDOK_AI_TRANSPOSITION_TABLE_HPP
