/**
 * @file test_mvgal_api.c
 * @brief Test suite for MVGAL API
 * 
 * Run with: ./test_mvgal_api --verbose
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <mvgal/mvgal.h>
#include <mvgal/mvgal_gpu.h>
#include <mvgal/mvgal_memory.h>

/* Test helpers */
static int tests_run = 0;
static int tests_passed = 0;
static int tests_failed = 0;

#define TEST(name) static void test_##name(void)
#define RUN_TEST(name) do { \
    printf("Running %s... ", #name); \
    tests_run++; \
    test_##name(); \
    printf("PASSED\n"); \
    tests_passed++; \
} while(0)

#define ASSERT(cond) do { \
    if (!(cond)) { \
        printf("FAILED at line %d: %s\n", __LINE__, #cond); \
        tests_failed++; \
        return; \
    } \
} while(0)

/* ============================================================================
 * Test 1: Library Initialization
 * ============================================================================ */

TEST(init_shutdown)
{
    ASSERT(mvgal_is_initialized() == false);
    
    mvgal_error_t err = mvgal_init(0);
    ASSERT(err == MVGAL_SUCCESS);
    ASSERT(mvgal_is_initialized() == true);
    
    mvgal_shutdown();
    ASSERT(mvgal_is_initialized() == false);
}

TEST(init_with_config)
{
    mvgal_error_t err = mvgal_init_with_config("/nonexistent/config.conf", 0);
    ASSERT(err == MVGAL_SUCCESS);  /* Should use defaults */
    
    mvgal_shutdown();
}

TEST(version_numbers)
{
    uint32_t major, minor, patch;
    mvgal_get_version_numbers(&major, &minor, &patch);
    
    ASSERT(major >= 0);
    ASSERT(minor >= 0);
    ASSERT(patch >= 0);
    
    const char *ver = mvgal_get_version();
    ASSERT(ver != NULL);
    ASSERT(strlen(ver) > 0);
}

/* ============================================================================
 * Test 2: Device Enumeration
 * ============================================================================ */

TEST(enumerate_gpus_null_check)
{
    mvgal_gpu_info_t *gpus = NULL;
    uint32_t count = 0;
    
    mvgal_error_t err = mvgal_init(0);
    ASSERT(err == MVGAL_SUCCESS);
    
    err = mvgal_enumerate_gpus(&gpus, &count);
    /* May fail if kernel module not loaded, but should not crash */
    
    if (err == MVGAL_SUCCESS) {
        if (count > 0) {
            ASSERT(gpus != NULL);
        }
    }
    
    mvgal_shutdown();
}

/* ============================================================================
 * Test 3: Context Management
 * ============================================================================ */

TEST(context_create_destroy)
{
    mvgal_error_t err = mvgal_init(0);
    ASSERT(err == MVGAL_SUCCESS);
    
    mvgal_context_t ctx = NULL;
    err = mvgal_context_create(&ctx);
    ASSERT(err == MVGAL_SUCCESS);
    ASSERT(ctx != NULL);
    
    mvgal_context_destroy(ctx);
    mvgal_shutdown();
}

TEST(context_set_strategy)
{
    mvgal_error_t err = mvgal_init(0);
    ASSERT(err == MVGAL_SUCCESS);
    
    mvgal_context_t ctx = NULL;
    err = mvgal_context_create(&ctx);
    ASSERT(err == MVGAL_SUCCESS);
    
    err = mvgal_set_strategy(ctx, MVGAL_STRATEGY_ROUND_ROBIN);
    ASSERT(err == MVGAL_SUCCESS);
    
    mvgal_distribution_strategy_t strategy = mvgal_get_strategy(ctx);
    ASSERT(strategy == MVGAL_STRATEGY_ROUND_ROBIN);
    
    mvgal_context_destroy(ctx);
    mvgal_shutdown();
}

/* ============================================================================
 * Test 4: Memory Management
 * ============================================================================ */

TEST(allocate_deallocate)
{
    mvgal_error_t err = mvgal_init(0);
    ASSERT(err == MVGAL_SUCCESS);
    
    uint64_t handle;
    err = mvgal_allocate_memory(1024 * 1024, 0, &handle);
    /* May fail without daemon, but should not crash */
    
    if (err == MVGAL_SUCCESS) {
        ASSERT(handle != 0);
        err = mvgal_free_memory(handle);
        ASSERT(err == MVGAL_SUCCESS);
    }
    
    mvgal_shutdown();
}

/* ============================================================================
 * Test 5: Synchronization
 * ============================================================================ */

TEST(synchronization)
{
    mvgal_error_t err = mvgal_init(0);
    ASSERT(err == MVGAL_SUCCESS);
    
    mvgal_context_t ctx = NULL;
    err = mvgal_context_create(&ctx);
    ASSERT(err == MVGAL_SUCCESS);
    
    mvgal_flush(ctx);
    mvgal_finish(ctx);
    mvgal_wait_idle(ctx, 1000);
    
    mvgal_context_destroy(ctx);
    mvgal_shutdown();
}

/* ============================================================================
 * Test 6: Statistics
 * ============================================================================ */

TEST(statistics)
{
    mvgal_error_t err = mvgal_init(0);
    ASSERT(err == MVGAL_SUCCESS);
    
    mvgal_stats_t stats;
    memset(&stats, 0, sizeof(stats));
    
    err = mvgal_get_stats(NULL, &stats);
    ASSERT(err == MVGAL_SUCCESS);
    
    mvgal_reset_stats(NULL);
    mvgal_shutdown();
}

/* ============================================================================
 * Main
 * ============================================================================ */

int main(int argc, char *argv[])
{
    int verbose = 0;
    
    if (argc > 1 && strcmp(argv[1], "--verbose") == 0) {
        verbose = 1;
    }
    
    printf("=== MVGAL API Test Suite ===\n\n");
    
    /* Run tests */
    RUN_TEST(init_shutdown);
    RUN_TEST(init_with_config);
    RUN_TEST(version_numbers);
    RUN_TEST(enumerate_gpus_null_check);
    RUN_TEST(context_create_destroy);
    RUN_TEST(context_set_strategy);
    RUN_TEST(allocate_deallocate);
    RUN_TEST(synchronization);
    RUN_TEST(statistics);
    
    /* Print results */
    printf("\n=== Test Results ===\n");
    printf("Tests run:    %d\n", tests_run);
    printf("Tests passed: %d\n", tests_passed);
    printf("Tests failed: %d\n", tests_failed);
    
    return tests_failed > 0 ? 1 : 0;
}