/**
 * @file test_barrier_translate.c
 * @brief Cross-Vendor Barrier Translation Unit Tests
 * 
 * Tests the public barrier translation API.
 */

#include "mvgal/mvgal.h"
#include "mvgal/mvgal_barrier_translate.h"
#include "mvgal/mvgal_log.h"

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

static int test_passed = 0;
static int test_failed = 0;

#define TEST_ASSERT(condition, message) \
    do { if (condition) { test_passed++; MVGAL_LOG_INFO("  ✓ %s", message); } \
         else { test_failed++; MVGAL_LOG_ERROR("  ✗ %s", message); } \
    } while (0)

/* ------------------------------------------------------------------ */
/*  Stage Normalization Tests                                          */
/* ------------------------------------------------------------------ */

static void test_stage_normalization(void)
{
    MVGAL_LOG_INFO("--- Stage normalization ---");

    /* Test individual stage bits using public API */
    mvgal_stage_t stage = mvgal_normalize_stage(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT);
    TEST_ASSERT(stage == MVGAL_STAGE_VERTEX_SHADER, "Vertex shader stage normalized");

    stage = mvgal_normalize_stage(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
    TEST_ASSERT(stage == MVGAL_STAGE_FRAGMENT_SHADER, "Fragment shader stage normalized");

    stage = mvgal_normalize_stage(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
    TEST_ASSERT(stage == MVGAL_STAGE_COMPUTE_SHADER, "Compute shader stage normalized");

    /* Test combined stages */
    stage = mvgal_normalize_stage(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | 
                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
    TEST_ASSERT(stage == (MVGAL_STAGE_VERTEX_SHADER | MVGAL_STAGE_FRAGMENT_SHADER),
                "Combined stages normalized");
}

/* ------------------------------------------------------------------ */
/*  Access Normalization Tests                                         */
/* ------------------------------------------------------------------ */

static void test_access_normalization(void)
{
    MVGAL_LOG_INFO("--- Access normalization ---");

    mvgal_access_t access = mvgal_normalize_access(VK_ACCESS_SHADER_READ_BIT);
    TEST_ASSERT(access == MVGAL_ACCESS_SHADER_READ, "Shader read access normalized");

    access = mvgal_normalize_access(VK_ACCESS_SHADER_WRITE_BIT);
    TEST_ASSERT(access == MVGAL_ACCESS_SHADER_WRITE, "Shader write access normalized");

    access = mvgal_normalize_access(VK_ACCESS_UNIFORM_READ_BIT);
    TEST_ASSERT(access == MVGAL_ACCESS_UNIFORM_READ, "Uniform read access normalized");

    access = mvgal_normalize_access(VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
    TEST_ASSERT(access == (MVGAL_ACCESS_TRANSFER_READ | MVGAL_ACCESS_TRANSFER_WRITE),
                "Combined access masks normalized");
}

/* ------------------------------------------------------------------ */
/*  Memory Barrier Normalization Tests                                   */
/* ------------------------------------------------------------------ */

static void test_memory_barrier_normalization(void)
{
    MVGAL_LOG_INFO("--- Memory barrier normalization ---");

    VkMemoryBarrier barrier = {
        .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
        .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
        .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
    };

    mvgal_normalized_barrier_t out;
    mvgal_normalize_memory_barrier(&barrier,
        VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
        VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
        VK_ACCESS_SHADER_WRITE_BIT,
        VK_ACCESS_SHADER_READ_BIT,
        &out);

    TEST_ASSERT(out.type == MVGAL_BARRIER_MEMORY, "Barrier type is MEMORY");
    TEST_ASSERT(out.src_stage & MVGAL_STAGE_COMPUTE_SHADER, "Source stage set");
    TEST_ASSERT(out.dst_stage & MVGAL_STAGE_VERTEX_SHADER, "Dest stage set");
    TEST_ASSERT(out.src_access == MVGAL_ACCESS_SHADER_WRITE, "Source access set");
    TEST_ASSERT(out.dst_access == MVGAL_ACCESS_SHADER_READ, "Dest access set");
}

/* ------------------------------------------------------------------ */
/*  Image Barrier Normalization Tests                                    */
/* ------------------------------------------------------------------ */

static void test_image_barrier_normalization(void)
{
    MVGAL_LOG_INFO("--- Image barrier normalization ---");

    VkImageMemoryBarrier barrier = {
        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
        .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
        .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
        .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
        .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
        .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
    };

    mvgal_normalized_barrier_t out;
    mvgal_normalize_image_barrier(&barrier,
        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
        &out);

    TEST_ASSERT(out.type == MVGAL_BARRIER_IMAGE, "Barrier type is IMAGE");
    TEST_ASSERT(out.src_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
                "Source layout preserved");
    TEST_ASSERT(out.dst_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
                "Dest layout preserved");
}

/* ------------------------------------------------------------------ */
/*  Vendor Barrier Emission Tests                                      */
/* ------------------------------------------------------------------ */

static void test_vendor_barrier_emission(void)
{
    MVGAL_LOG_INFO("--- Vendor barrier emission ---");

    mvgal_normalized_barrier_t barrier = {
        .type = MVGAL_BARRIER_MEMORY,
        .src_stage = MVGAL_STAGE_COMPUTE_SHADER,
        .dst_stage = MVGAL_STAGE_FRAGMENT_SHADER,
        .src_access = MVGAL_ACCESS_SHADER_WRITE,
        .dst_access = MVGAL_ACCESS_SHADER_READ,
    };

    /* Test each vendor emitter - they accept NULL cmd_buf for validation */
    barrier.target_vendor = MVGAL_VENDOR_AMD;
    int result = mvgal_emit_amd_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "AMD barrier emission succeeds");

    barrier.target_vendor = MVGAL_VENDOR_NVIDIA;
    result = mvgal_emit_nvidia_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "NVIDIA barrier emission succeeds");

    barrier.target_vendor = MVGAL_VENDOR_INTEL;
    result = mvgal_emit_intel_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "Intel barrier emission succeeds");

    barrier.target_vendor = MVGAL_VENDOR_MOORE_THREADS;
    result = mvgal_emit_mtt_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "MTT barrier emission succeeds");
}

/* ------------------------------------------------------------------ */
/*  Dispatcher Test                                                    */
/* ------------------------------------------------------------------ */

static void test_barrier_dispatcher(void)
{
    MVGAL_LOG_INFO("--- Barrier dispatcher ---");

    mvgal_normalized_barrier_t barrier = {
        .type = MVGAL_BARRIER_MEMORY,
        .src_stage = MVGAL_STAGE_COMPUTE_SHADER,
        .dst_stage = MVGAL_STAGE_FRAGMENT_SHADER,
    };

    /* Test dispatcher for each vendor */
    barrier.target_vendor = MVGAL_VENDOR_AMD;
    int result = mvgal_emit_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "Dispatcher routes to AMD");

    barrier.target_vendor = MVGAL_VENDOR_NVIDIA;
    result = mvgal_emit_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "Dispatcher routes to NVIDIA");

    barrier.target_vendor = MVGAL_VENDOR_INTEL;
    result = mvgal_emit_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "Dispatcher routes to Intel");

    barrier.target_vendor = MVGAL_VENDOR_MOORE_THREADS;
    result = mvgal_emit_barrier(&barrier, NULL);
    TEST_ASSERT(result == 0, "Dispatcher routes to MTT");

    /* Test null handling */
    result = mvgal_emit_barrier(NULL, NULL);
    TEST_ASSERT(result == -1, "Dispatcher handles NULL barrier");
}

/* ------------------------------------------------------------------ */
/*  main                                                              */
/* ------------------------------------------------------------------ */

int main(void)
{
    printf("\n============================================================\n");
    printf("  MVGAL Barrier Translation Unit Tests\n");
    printf("============================================================\n\n");

    test_stage_normalization();
    test_access_normalization();
    test_memory_barrier_normalization();
    test_image_barrier_normalization();
    test_vendor_barrier_emission();
    test_barrier_dispatcher();

    printf("\n============================================================\n");
    printf("  Test Summary\n");
    printf("============================================================\n");
    printf("  Passed: %d\n", test_passed);
    printf("  Failed: %d\n", test_failed);
    printf("  Total:  %d\n", test_passed + test_failed);
    printf("============================================================\n\n");

    return (test_failed > 0) ? EXIT_FAILURE : EXIT_SUCCESS;
}