BareGit
#pragma once

#include <cstdarg>
#include <cstdint>
#include <map>
#include <string>
#include <vector>

#include "protocol.hpp"

namespace nethack_mcp
{

/// Translate the pinned NetHack shim into owned observations and input.
class WindowAdapter
{
public:
    /// Bind an adapter to the worker's private IPC channel.
    WindowAdapter(FramedChannel& channel, std::string game_id);

    WindowAdapter(const WindowAdapter&) = delete;
    WindowAdapter& operator=(const WindowAdapter&) = delete;

    /// Install this adapter as the callback target for NetHack.
    void install();

    /// Send the native NetHack terminal reason over the worker IPC channel.
    static void reportTerminalResult(int how);

private:
    struct MenuEntry
    {
        int entry_id = 0;
        std::string text;
        bool selectable = false;
        bool selected = false;
        char letter = 0;
        std::vector<unsigned char> identifier;
    };

    static void callback(const char* name, void* return_ptr,
                         const char* format, ...);
    void handleCallback(const char* name, void* return_ptr,
                        const char* format, std::va_list arguments);

    Json makeSnapshot() const;
    Json waitForInput(Json pending);
    Json makePending(std::string kind, std::string source) const;
    void publishSnapshot(Json snapshot);
    void addMessage(const char* message);
    void setIntegerReturn(void* return_ptr, int value) const;
    void setCharacterReturn(void* return_ptr, char value) const;
    void copyTextReturn(void* return_ptr, const std::string& text) const;
    int resolveCommand(const std::string& command) const;

    FramedChannel& channel_;
    std::string game_id_;
    std::uint64_t sequence_ = 0;
    std::uint64_t input_id_ = 0;
    int next_window_id_ = 1;
    std::map<int, int> window_types_;
    int active_menu_window_ = -1;
    int next_menu_entry_id_ = 1;
    int cursor_x_ = 1;
    int cursor_y_ = 0;
    std::vector<std::string> map_rows_;
    std::vector<Json> messages_;
    bool messages_truncated_ = false;
    Json status_ = Json::object();
    Json inventory_ = {
        {"known", false},
        {"stale", true},
        {"entries", Json::array()},
    };
    std::vector<MenuEntry> menu_entries_;
    std::string menu_prompt_;
    std::string text_window_;
    bool inventory_requested_ = false;
    std::map<int, std::string> status_fields_;

    static WindowAdapter* active_adapter_;
};

} // namespace nethack_mcp