#include <stdio.h>

#include "../Tests.hpp"
#include "core/Logger.hpp"
#include "core/Terminal.hpp"
#include "core/Test.hpp"
#include "core/Utility.hpp"

#define KEY_CASE(key)           \
    case key: puts(#key); break

void testTerminal(bool tty) {
    Core::IntVector2 size = Core::getTerminalSize();
    if(tty) {
        TEST_TRUE(size[0] > 0);
        TEST_TRUE(size[1] > 0);
        TEST_FALSE(Core::enterRawTerminal());
        TEST_FALSE(Core::leaveRawTerminal());
    } else {
        TEST(0, size[0]);
        TEST(0, size[1]);
    }

    Core::enterAlternativeTerminal();
    Core::clearTerminal();
    Core::resetCursor();
    LOG_ERROR("Not visible!");
    Core::leaveAlternativeTerminal();

    LOG_ERROR("Not visible!");
    Core::moveCursorUp(2);
    Core::moveCursorDown(1);
    Core::moveCursorLeft(3);
    Core::moveCursorRight(3);
    Core::clearTerminalLine();

    Core::hideCursor();
    Core::showCursor();

    u64 u = TERMINAL_KEY_F5 | TERMINAL_KEY_SHIFT;
    TEST_TRUE(Core::isSpecialChar(u));
    Core::SpecialChar s = Core::convertToSpecialChar(u);
    TEST(TERMINAL_KEY_F5, s.key);
    TEST_FALSE(s.alt);
    TEST_FALSE(s.control);
    TEST_TRUE(s.shift);
}

void testInteractiveTerminal(void) {
    Core::enterAlternativeTerminal();

    Core::resetCursor();
    Core::hideCursor();
    puts("Hi there");
    LOG_WARNING("This is a test");
    Core::IntVector2 v = Core::getTerminalSize();
    printf("%d %d\n", v[0], v[1]);
    Core::clearTerminal();
    Core::resetCursor();
    Core::showCursor();
    puts("the final!!!");
    Core::sleepMillis(500);

    Core::enterRawTerminal();

    while(true) {
        u64 c = Core::getRawChar();
        if(c == 'q') {
            break;
        } else if(c == 0) {
            continue;
        } else if(Core::isSpecialChar(c)) {
            Core::SpecialChar sc = Core::convertToSpecialChar(c);
            if(sc.shift) {
                printf("SHIFT + ");
            }
            if(sc.control) {
                printf("CTRL + ");
            }
            if(sc.alt) {
                printf("ALT + ");
            }
            switch(sc.key) {
                KEY_CASE(TERMINAL_KEY_ARROW_LEFT);
                KEY_CASE(TERMINAL_KEY_ARROW_RIGHT);
                KEY_CASE(TERMINAL_KEY_ARROW_UP);
                KEY_CASE(TERMINAL_KEY_ARROW_DOWN);
                KEY_CASE(TERMINAL_KEY_DELETE);
                KEY_CASE(TERMINAL_KEY_F1);
                KEY_CASE(TERMINAL_KEY_F2);
                KEY_CASE(TERMINAL_KEY_F3);
                KEY_CASE(TERMINAL_KEY_F4);
                KEY_CASE(TERMINAL_KEY_F5);
                KEY_CASE(TERMINAL_KEY_F6);
                KEY_CASE(TERMINAL_KEY_F7);
                KEY_CASE(TERMINAL_KEY_F8);
                KEY_CASE(TERMINAL_KEY_F9);
                KEY_CASE(TERMINAL_KEY_F10);
                KEY_CASE(TERMINAL_KEY_F11);
                KEY_CASE(TERMINAL_KEY_F12);
                KEY_CASE(TERMINAL_KEY_PAGE_UP);
                KEY_CASE(TERMINAL_KEY_PAGE_DOWN);
                KEY_CASE(TERMINAL_KEY_HOME);
                KEY_CASE(TERMINAL_KEY_END);
                default: printf("%lu\n", sc.key); break;
            }
        } else {
            printf("%lu\n", c);
        }
    }

    Core::leaveRawTerminal();

    Core::leaveAlternativeTerminal();
}