/**
 * MVGAL - Multi-Vendor GPU Aggregation Layer for Linux
 * 
 * Test Infrastructure Implementation
 * 
 * SPDX-License-Identifier: GPL-2.0-only
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/ktime.h>

#include "mvgal_test.h"

/* Test results storage */
static struct {
    atomic_t total_tests;
    atomic_t passed;
    atomic_t failed;
    atomic_t skipped;
    char results_json[4096];
} test_stats;

/* Test suites list */
static LIST_HEAD(suite_list);
static DEFINE_MUTEX(suite_lock);

/* Test cases list */
static LIST_HEAD(test_list);
static DEFINE_MUTEX(test_lock);

/*
 * mvgal_test_register_suite - Register a test suite
 */
int mvgal_test_register_suite(struct mvgal_test_suite *suite)
{
    if (!suite) {
        return -EINVAL;
    }

    mutex_lock(&suite_lock);
    list_add_tail(&suite->node, &suite_list);
    mutex_unlock(&suite_lock);

    pr_info("MVGAL_TEST: Registered suite '%s'\n", suite->name);
    return 0;
}
EXPORT_SYMBOL_GPL(mvgal_test_register_suite);

/*
 * mvgal_test_register_test - Register a test case
 */
int mvgal_test_register_test(struct mvgal_test_case *test)
{
    if (!test) {
        return -EINVAL;
    }

    mutex_lock(&test_lock);
    list_add_tail(&test->node, &test_list);
    mutex_unlock(&test_lock);

    pr_info("MVGAL_TEST: Registered test '%s'\n", test->name);
    return 0;
}
EXPORT_SYMBOL_GPL(mvgal_test_register_test);

/*
 * mvgal_test_run_all - Run all registered tests
 */
int mvgal_test_run_all(void)
{
    struct mvgal_test_suite *suite;
    struct mvgal_test_case *test;
    int failed = 0;
    int passed = 0;
    int skipped = 0;

    pr_info("MVGAL_TEST: Starting all tests\n");

    atomic_set(&test_stats.total_tests, 0);
    atomic_set(&test_stats.passed, 0);
    atomic_set(&test_stats.failed, 0);
    atomic_set(&test_stats.skipped, 0);

    /* Run suite initialization */
    list_for_each_entry(suite, &suite_list, node) {
        if (suite->init) {
            if (suite->init() < 0) {
                pr_err("MVGAL_TEST: Suite '%s' init failed\n", suite->name);
            }
        }
    }

    /* Run all tests */
    list_for_each_entry(test, &test_list, node) {
        atomic_inc(&test_stats.total_tests);

        pr_info("MVGAL_TEST: Running '%s'...\n", test->name);

        /* Check skip conditions */
        if (test->skip_if_no_dmabuf && !mvgal_dmabuf_supported()) {
            pr_info("MVGAL_TEST: Skipping '%s' (no DMABUF)\n", test->name);
            atomic_inc(&test_stats.skipped);
            skipped++;
            continue;
        }

        if (test->skip_if_no_p2p && !mvgal_p2p_supported()) {
            pr_info("MVGAL_TEST: Skipping '%s' (no P2P)\n", test->name);
            atomic_inc(&test_stats.skipped);
            skipped++;
            continue;
        }

        if (test->min_gpu_count > mvgal_gpu_count()) {
            pr_info("MVGAL_TEST: Skipping '%s' (need %u GPUs, have %u)\n",
                    test->name, test->min_gpu_count, mvgal_gpu_count());
            atomic_inc(&test_stats.skipped);
            skipped++;
            continue;
        }

        /* Run the test */
        int result = test->test_func();
        if (result == MVGAL_TEST_PASS) {
            atomic_inc(&test_stats.passed);
            passed++;
            pr_info("MVGAL_TEST: PASSED: '%s'\n", test->name);
        } else {
            atomic_inc(&test_stats.failed);
            failed++;
            pr_err("MVGAL_TEST: FAILED: '%s' (result: %d)\n", test->name, result);
        }
    }

    /* Cleanup suites */
    list_for_each_entry(suite, &suite_list, node) {
        if (suite->cleanup) {
            suite->cleanup();
        }
    }

    pr_info("MVGAL_TEST: Results: %d passed, %d failed, %d skipped\n",
            passed, failed, skipped);

    return failed > 0 ? MVGAL_TEST_FAIL : MVGAL_TEST_PASS;
}
EXPORT_SYMBOL_GPL(mvgal_test_run_all);

/*
 * mvgal_test_get_results_json - Get test results as JSON
 */
const char *mvgal_test_get_results_json(void)
{
    static char json[4096];
    int len;

    len = snprintf(json, sizeof(json),
                   "{\n"
                   "  \"total\": %d,\n"
                   "  \"passed\": %d,\n"
                   "  \"failed\": %d,\n"
                   "  \"skipped\": %d\n"
                   "}\n",
                   atomic_read(&test_stats.total_tests),
                   atomic_read(&test_stats.passed),
                   atomic_read(&test_stats.failed),
                   atomic_read(&test_stats.skipped));

    if (len >= sizeof(json)) {
        return "{}";
    }

    return json;
}