/**
 * mvgal-dmabuf-matrix — Report P2P and DMA-BUF transfer paths between detected GPUs.
 *
 * Writes a Markdown matrix to stdout or -o FILE for hardware validation (M2 gate).
 *
 * SPDX-License-Identifier: MIT
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "mvgal/mvgal.h"
#include "mvgal/mvgal_gpu.h"
#include "mvgal/mvgal_p2p_dma.h"

static const char *vendor_name(uint32_t vendor_id)
{
    switch (vendor_id) {
    case 0x1002: return "AMD";
    case 0x10de: return "NVIDIA";
    case 0x8086: return "Intel";
    case 0x1ed5: return "MTT";
    default:     return "Other";
    }
}

static const char *path_label(bool p2p, bool same_rc)
{
    if (p2p && same_rc) return "PCIe P2P (same root complex)";
    if (p2p)            return "PCIe P2P (probed)";
    if (same_rc)        return "DMA-BUF / staging (same domain)";
    return "Host staging (portable)";
}

int main(int argc, char *argv[])
{
    const char *out_path = NULL;
    FILE *out = stdout;
    mvgal_gpu_descriptor_t gpus[MVGAL_MAX_GPUS];
    uint8_t matrix[MVGAL_MAX_GPUS * MVGAL_MAX_GPUS];
    uint32_t gpu_count = 0;
    int32_t n;

    for (int i = 1; i < argc; i++) {
        if ((strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) && i + 1 < argc) {
            out_path = argv[++i];
        } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
            printf("Usage: mvgal-dmabuf-matrix [-o report.md]\n");
            return 0;
        }
    }

    if (out_path) {
        out = fopen(out_path, "w");
        if (!out) {
            perror(out_path);
            return EXIT_FAILURE;
        }
    }

    if (mvgal_init(0) != MVGAL_SUCCESS) {
        fprintf(stderr, "mvgal_init failed\n");
        return EXIT_FAILURE;
    }

    n = mvgal_gpu_enumerate(gpus, MVGAL_MAX_GPUS);
    if (n < 0) {
        n = 0;
    }
    gpu_count = (uint32_t)n;

    memset(matrix, 0, sizeof(matrix));
    if (mvgal_p2p_build_matrix(matrix, sizeof(matrix), &gpu_count) != MVGAL_SUCCESS) {
        fprintf(stderr, "warning: P2P matrix build failed, using enumeration count only\n");
    }

    time_t now = time(NULL);
    struct tm tm_buf;
    gmtime_r(&now, &tm_buf);
    char ts[64];
    strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S UTC", &tm_buf);

    fprintf(out, "# MVGAL DMA-BUF / P2P Matrix\n\n");
    fprintf(out, "**Generated:** %s  \n", ts);
    fprintf(out, "**GPUs:** %u  \n\n", gpu_count);

    fprintf(out, "## Detected devices\n\n");
    fprintf(out, "| Index | Vendor | Device | Name | PCI |\n");
    fprintf(out, "|-------|--------|--------|------|-----|\n");
    for (uint32_t i = 0; i < gpu_count; i++) {
        fprintf(out, "| %u | %s | 0x%04x | %s | %04x:%02x:%02x.%u |\n",
                i,
                vendor_name(gpus[i].vendor_id),
                gpus[i].device_id,
                gpus[i].name,
                gpus[i].pci_domain,
                gpus[i].pci_bus,
                gpus[i].pci_device,
                gpus[i].pci_function);
    }
    fprintf(out, "\n");

    fprintf(out, "## Pairwise transfer path (advisory)\n\n");
    fprintf(out, "| Src \\ Dst |");
    for (uint32_t j = 0; j < gpu_count; j++) {
        fprintf(out, " %u |", j);
    }
    fprintf(out, "\n|-----------|");
    for (uint32_t j = 0; j < gpu_count; j++) {
        fprintf(out, "------|");
    }
    fprintf(out, "\n");

    for (uint32_t i = 0; i < gpu_count; i++) {
        fprintf(out, "| **%u** |", i);
        for (uint32_t j = 0; j < gpu_count; j++) {
            if (i == j) {
                fprintf(out, " — |");
                continue;
            }
            mvgal_p2p_caps_t caps = {0};
            bool p2p = false;
            bool same_rc = mvgal_p2p_check_pcie_topology(i, j);
            if (mvgal_p2p_query_caps(i, j, &caps) == MVGAL_SUCCESS) {
                p2p = caps.supported;
            } else if (i < MVGAL_MAX_GPUS && j < MVGAL_MAX_GPUS) {
                p2p = matrix[i * MVGAL_MAX_GPUS + j] != 0;
            }
            fprintf(out, " %s |", path_label(p2p, same_rc));
        }
        fprintf(out, "\n");
    }

    fprintf(out, "\n## Userspace DMA-BUF self-test\n\n");
    fprintf(out, "Run: `ctest -R test_dmabuf_integration` or `./test_dmabuf_integration` after build.\n\n");
    fprintf(out, "## Notes\n\n");
    fprintf(out, "- Labels are **capability hints**; real dma-buf import/export must be validated per driver pair.\n");
    fprintf(out, "- Regenerate after driver or topology changes: `mvgal-dmabuf-matrix -o docs/HARDWARE_DMABUF_MATRIX.md`\n");

    mvgal_shutdown();

    if (out != stdout) {
        fclose(out);
        printf("Wrote %s\n", out_path);
    }

    return (gpu_count == 0) ? EXIT_FAILURE : EXIT_SUCCESS;
}
