#include <clocale>
#include <cstdio>
#include <cstring>

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

static void finalize() {
    Core::finalizeTests();
    Core::printMemoryReport();
}

static void onExit(int code, void* data) {
    unsigned int i = *static_cast<unsigned int*>(data);
    LOG_WARNING("Hello from exit #: #", code, i);
    finalize();
}

int main(int argAmount, const char** args) {
    if(argAmount >= 2 && strcmp(args[1], "help") == 0) {
        puts("alloc");
        puts("realloc");
        puts("pre_canary");
        puts("pre_canary_new");
        puts("pre_canary_new_array");
        puts("post_canary");
        puts("test;ignore");
        puts("terminal");
        puts("light;testData/readLineTest");
        return 0;
    }
    setlocale(LC_ALL, "en_US.utf8");
    bool light = false;
    for(int i = 0; i < argAmount; i++) {
        if(strcmp(args[i], "light") == 0) {
            light = true;
        } else if(strcmp(args[i], "alloc") == 0) {
            testInvalidAllocate();
        } else if(strcmp(args[i], "realloc") == 0) {
            testInvalidReallocate();
        } else if(strcmp(args[i], "pre_canary") == 0) {
            testPreCanary();
        } else if(strcmp(args[i], "pre_canary_new") == 0) {
            testPreCanaryNew();
        } else if(strcmp(args[i], "pre_canary_new_array") == 0) {
            testPreCanaryNewArray();
        } else if(strcmp(args[i], "post_canary") == 0) {
            testPostCanary();
        } else if(strcmp(args[i], "test") == 0) {
            testTest();
            return 0;
        } else if(strcmp(args[i], "terminal") == 0) {
            testTerminal(true);
            finalize();
            return 0;
        } else if(strcmp(args[i], "iterminal") == 0) {
            testInteractiveTerminal();
            return 0;
        }
    }

    testList(light);
    testUniquePointer();
    testVector();
    testMath();
    testArray();
    // testBitArray();
    testBox();
    // testBuffer(light);
    // testComponents();
    testFile();
    testFrustum();
    testHashMap(light);
    testMatrix();
    testPlane();
    testQuaternion();
    // testQueue();
    testRandom(light);
    if(light) {
        // testReadLine();
    }
    // testSpinLock();
    testTerminal(!light);
    testUnicode();
    testUtility(light);
    testView();

    logLevel = LogLevel::WARNING;
    LOG_DEBUG("You won't see this!");
    logLevel = LogLevel::DEBUG;

    unsigned int data = 123'456'789;
    Core::setExitHandler(onExit, &data);

    EXIT(1);
}