#include <atomic>
#include <thread>
#include <mutex>

#include <readline/readline.h>
#include <readline/history.h>
#include <poll.h>
#include <unistd.h>

#include "server/commands/ConsoleEditor.h"
#include "gaming-core/utils/RingBuffer.h"

#include <iostream>

struct Setup {
    std::atomic_bool running;
    std::mutex queueMutex;
    RingBuffer<char*, 8> queue;
    std::thread readThread;

    static Setup instance;

    Setup() : running(true), readThread(&Setup::loop, this) {
        rl_bind_key('\t', rl_insert);
    }

    ~Setup() {
        running = false;
        readThread.join();
        rl_callback_handler_remove();
        rl_clear_visible_line();
    }

    static void onLineRead(char* line) {
        std::lock_guard<std::mutex> lg(instance.queueMutex);
        add_history(line);
        instance.queue.write(line);
    }

    void loop() {
        rl_callback_handler_install("> ", onLineRead);
        rl_set_keyboard_input_timeout(1);
        while(running) {
            struct pollfd fds;
            fds.fd = STDIN_FILENO;
            fds.events = POLLIN;
            fds.revents = 0;
            int result = poll(&fds, 1, 1);
            if(result > 0) {
                rl_callback_read_char();
            }
        }
    }
};

Setup Setup::instance;

void ConsoleEditor::clearPrintLine() {
    rl_clear_visible_line();
}

void ConsoleEditor::printLine() {
    rl_forced_update_display();
}

bool ConsoleEditor::readCommand(RawCommand& buffer) {
    std::lock_guard<std::mutex> lg(Setup::instance.queueMutex);
    if(Setup::instance.queue.canRead()) {
        char* data = Setup::instance.queue.read();
        buffer.clear().append(static_cast<const char*>(data));
        free(data);
        return true;
    }
    return false;
}