//
// Created by Dan Crosby on 2025-01-15.
//

#ifndef EAGLE0_GAMESTATEW_HPP
#define EAGLE0_GAMESTATEW_HPP

#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/FlatbufferWrapper.hpp"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/game_state.hpp"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/unit.hpp"

namespace shardok {

/**
 * @class GameStateW
 * @brief A wrapper class for the FlatBuffer-generated GameState type.
 *
 * GameStateW extends the Wrapper class to provide additional functionality
 * for working with the net::eagle0::shardok::storage::fb::GameState type.
 * It inherits all constructors and assignment operators from the base Wrapper
 * class, enabling seamless integration with the underlying FlatBuffer type.
 *
 * This class is part of the shardok namespace and is designed to simplify
 * interactions with the GameState FlatBuffer type while maintaining the
 * flexibility and functionality of the Wrapper base class.
 */
class GameStateW : public Wrapper<net::eagle0::shardok::storage::fb::GameState> {
public:
    using BaseType = Wrapper<net::eagle0::shardok::storage::fb::GameState>;
    using Unit = net::eagle0::shardok::storage::fb::Unit;

    // Inherit all constructors from Wrapper
    using BaseType::BaseType;

    // Default constructor
    GameStateW() : BaseType() {}

    // Copy constructor
    GameStateW(const GameStateW& other) : BaseType(other) {}

    // Move constructor
    GameStateW(GameStateW&& other) noexcept : BaseType(std::move(other)) {}

    // Copy assignment
    GameStateW& operator=(const GameStateW& other) {
        BaseType::operator=(other);
        return *this;
    }

    // Move assignment
    GameStateW& operator=(GameStateW&& other) noexcept {
        BaseType::operator=(std::move(other));
        return *this;
    }

    // Constructor from base type
    GameStateW(const BaseType& base) : BaseType(base) {}
    GameStateW(BaseType&& base) : BaseType(std::move(base)) {}

    /**
     * @brief Get the unit occupying the specified coordinates using occupied tiles bitfield.
     * @param coords The coordinates to check.
     * @return Pointer to the unit at the coordinates, or nullptr if none.
     *
     * Fast path: O(1) bitfield check for empty tiles (~90% of cases).
     * Slow path: O(n) unit search only when bitfield indicates occupation (~10% of cases).
     */
    [[nodiscard]] auto GetOccupant(const net::eagle0::shardok::storage::fb::Coords& coords) const
            -> const Unit*;

    /**
     * @brief Get the known enemy unit occupying the specified coordinates using occupied tiles
     * bitfield.
     * @param playerId The player ID to check enemies for.
     * @param allyPids Vector of allied player IDs.
     * @param coords The coordinates to check.
     * @return Pointer to the enemy unit at the coordinates, or nullptr if none.
     *
     * Uses the bitfield-optimized GetOccupant() internally.
     */
    [[nodiscard]] auto GetKnownEnemyOccupant(
            PlayerId playerId,
            const std::vector<PlayerId>& allyPids,
            const net::eagle0::shardok::storage::fb::Coords& coords) const -> const Unit*;

    /**
     * @brief Update the occupied tiles bitfield when a unit changes position.
     * @param oldCoords The previous coordinates (use {-1, -1} if unit was off-map).
     * @param newCoords The new coordinates (use {-1, -1} if unit is now off-map).
     */
    void UpdateOccupiedTile(
            const net::eagle0::shardok::storage::fb::Coords& oldCoords,
            const net::eagle0::shardok::storage::fb::Coords& newCoords);

    /**
     * @brief Get the occupied tiles bitfield for efficient tile occupancy checking.
     * @return Pointer to the bitfield data, or nullptr if not available.
     *
     * Returns the raw bitfield where bit at index (row*column_count + col) indicates
     * if that tile is occupied. Useful for caching the bitfield to avoid repeated
     * GameStateW lookups in performance-critical code like MoveCommand.
     */
    [[nodiscard]] auto GetOccupiedTilesBitfield() const -> const flatbuffers::Vector<uint8_t>*;
};

}  // namespace shardok

#endif  // EAGLE0_GAMESTATEW_HPP