// Kyler Olsen
// YREA SLS
// SLS Tests
// November 2025

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "sls/errors.h"
#include "tests/tests.h"

static const Boolean PRINT_SUCCESSFUL_TESTS = FALSE;

const SlsStr TEST_FILE_NAME = SLS_STR_CONST("TEST_FILE.SLS");

typedef struct {
    uint16_t errored;
    uint16_t error_failed;
    uint16_t logic_error_failed;
    uint16_t logic_failed;
    uint16_t passed;
    uint16_t not_implemented;
    uint16_t total;
} TestCounts;

static void test_report(TestsReport reports, TestCounts *counts) {
    counts->total += reports.count;
    for (size_t i = 0; i < reports.count; i++) {
        switch (reports.tests[i].status) {
        case TEST_ERROR:
            // Bright Red
            printf("\x1b[91mTest errored: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].error.message.str);
            counts->errored += 1;
            break;
        case TEST_ERROR_FAIL:
            // Magenta
            printf("\x1b[35mLexing errored: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].error.message.str);
            counts->error_failed += 1;
            break;
        case TEST_LOGIC_ERROR_FAIL:
            // Red
            printf("\x1b[31mTest failed with lexical error: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].error.message.str);
            counts->logic_error_failed += 1;
            sls_str_free(&reports.tests[i].message);
            break;
        case TEST_LOGIC_FAIL:
            // Red
            printf("\x1b[31mTest failed: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].message.str);
            counts->logic_failed += 1;
            sls_str_free(&reports.tests[i].message);
            break;
        case TEST_PASS:
            // Green
            if (PRINT_SUCCESSFUL_TESTS)
                printf("\x1b[32mTest passed: %s\n\x1b[0m", reports.tests[i].name.str);
            counts->passed += 1;
            break;
        case TEST_NOT_IMPLEMENTED:
            // Blue
            printf("\x1b[34mTest not implemented: %s\n\x1b[0m", reports.tests[i].name.str);
            counts->not_implemented += 1;
            break;
        default:
            // Bright Red
            printf("\x1b[91mTest errored: %s\n\tUnknown test result status.\n\x1b[0m", reports.tests[i].name.str);
            counts->errored += 1;
            break;
        }
    }
}

int main(void) {
    TestCounts counts = {
        .errored = 0,
        .error_failed = 0,
        .logic_error_failed = 0,
        .logic_failed = 0,
        .passed = 0,
        .not_implemented = 0,
        .total = 0,
    };

    printf("    ========== SlsStr Tests ==========\n");
    test_report(run_string_tests(), &counts);
    printf("    ========== Lexer Tests ==========\n");
    test_report(run_lexer_tests(), &counts);
    printf("    ========== Hash Table Tests ==========\n");
    test_report(run_hash_table_tests(), &counts);
    printf("    ========== Extra Tests ==========\n");
    test_report(run_extra_tests(), &counts);

    printf("    ========== Tests Overview ==========\n");
    if (counts.errored > 0)
        // Bright Red
        printf("\x1b[91m%d of %d tests encountered an error.\n\x1b[0m", counts.errored, counts.total);
    if (counts.error_failed > 0)
        // Magenta
        printf("\x1b[35m%d of %d tests failed because of an interpreter error.\n\x1b[0m", counts.error_failed, counts.total);
    if (counts.logic_error_failed > 0)
        // Red
        printf("\x1b[31m%d of %d tests failed because of a lexical, parsing, or runtime error.\n\x1b[0m", counts.logic_error_failed, counts.total);
    if (counts.logic_failed > 0)
        // Red
        printf("\x1b[31m%d of %d tests failed because of a logical error.\n\x1b[0m", counts.logic_failed, counts.total);
    if (counts.passed > 0)
        // Green
        printf("\x1b[32m%d of %d tests passed.\n\x1b[0m", counts.passed, counts.total);
    if (counts.not_implemented > 0)
        // Blue
        printf("\x1b[34m%d of %d tests are not implemented.\n\x1b[0m", counts.not_implemented, counts.total);

    return 0;
}
