// SPDX-License-Identifier: BSL-1.0
#ifndef TERMPAINT_TERMINALOUTPUT_INCLUDED
#define TERMPAINT_TERMINALOUTPUT_INCLUDED

#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>

extern int driverFd;

void resetAndClear();

class Queue {
public:
    void push(std::unique_ptr<std::string>&& item) {
        std::unique_lock<std::mutex> lock(mutex);
        queue.push(std::move(item));
        lock.unlock();
        cond.notify_one();
    }

    std::unique_ptr<std::string> pop() {
        std::unique_lock<std::mutex> lock(mutex);
        while (queue.empty()) {
            if (cond.wait_for(lock, std::chrono::milliseconds(500)) == std::cv_status::timeout) {
                puts("Timeout while waiting for message. Aborting\n.");
                abort();
            }
        }
        auto item = move(queue.front());
        queue.pop();
        return item;
    }

    void clear() {
        std::unique_lock<std::mutex> lock(mutex);
        while (!queue.empty()) {
            queue.pop();
        }
    }

private:
    std::mutex mutex;
    std::condition_variable cond;
    std::queue<std::unique_ptr<std::string>> queue;
};

extern Queue queue;
extern Queue asyncQueue;

class CapturedCell {
public:
    int x;
    int y;
    std::string data;
    std::string fg, bg, deco; // empty is default (name for named colors, number for palette colors or #rrggbb
    int style = 0;
    int width = 1;
    bool erased = false;

public:
    CapturedCell withFg(std::string val) {
        auto r = *this;
        r.fg = val;
        return r;
    }
    CapturedCell withBg(std::string val) {
        auto r = *this;
        r.bg = val;
        return r;
    }
    CapturedCell withDeco(std::string val) {
        auto r = *this;
        r.deco = val;
        return r;
    }
    CapturedCell withStyle(int val) {
        auto r = *this;
        r.style = val;
        return r;
    }
    CapturedCell setErased() {
        auto r = *this;
        r.erased = true;
        return r;
    }
};

class CapturedRow {
public:
    std::vector<CapturedCell> cells;
    bool softWrapped = false;
};

class CapturedState {
public:
    std::vector<CapturedRow> rows;
    int width = -1, height = -1;
    int cursorX = -1, cursorY = -1;
    bool cursorVisible = true;
    bool cursorBlink = true;
    std::string cursorShape;
    std::string mouseMode;
    bool altScreen = false;
    bool invScreen = false;
    std::string title, iconTitle;
    CapturedCell sgrState;
};

CapturedState capture();

#endif
