/**
 * @file mvgal_cmd_dag.h
 * @brief Command Buffer DAG - Phase 3 Cross-Vendor Translation
 *
 * Represents Vulkan command buffers as a directed acyclic graph (DAG)
 * that can be translated and emitted for different GPU vendors.
 */

#ifndef MVGAL_CMD_DAG_H
#define MVGAL_CMD_DAG_H

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <vulkan/vulkan.h>
#include <mvgal/mvgal_types.h>

#ifdef __cplusplus
extern "C" {
#endif

/* ------------------------------------------------------------------ */
/*  Command Types                                                       */
/* ------------------------------------------------------------------ */

typedef enum {
    MVGAL_CMD_DRAW = 0,
    MVGAL_CMD_DRAW_INDIRECT = 1,
    MVGAL_CMD_DISPATCH = 2,
    MVGAL_CMD_DISPATCH_INDIRECT = 3,
    MVGAL_CMD_BLIT = 4,
    MVGAL_CMD_CLEAR = 5,
    MVGAL_CMD_COPY = 6,
    MVGAL_CMD_BARRIER = 7,
    MVGAL_CMD_BIND_DESCRIPTOR_SET = 8,
    MVGAL_CMD_BIND_PIPELINE = 9,
    MVGAL_CMD_NEXT_SUBPASS = 10,
} mvgal_cmd_type_t;

/* ------------------------------------------------------------------ */
/*  DAG Node                                                            */
/* ------------------------------------------------------------------ */

typedef struct mvgal_cmd_node {
    mvgal_cmd_type_t type;
    
    /* Union of all possible arguments */
    union {
        struct {
            uint32_t vertex_count;
            uint32_t instance_count;
            uint32_t first_vertex;
            int32_t first_instance;
        } draw;
        
        struct {
            VkBuffer buffer;
            VkDeviceSize offset;
            uint32_t count;
        } draw_indirect;
        
        struct {
            uint32_t group_x;
            uint32_t group_y;
            uint32_t group_z;
        } dispatch;
        
        struct {
            VkImage src_image;
            VkImage dst_image;
            VkOffset3D src_offset;
            VkOffset3D dst_offset;
            VkExtent3D extent;
        } blit;
        
        struct {
            VkImage image;
            VkRect2D render_area;
            VkClearValue clear_value;
        } clear;
        
        struct {
            VkBuffer src_buffer;
            VkBuffer dst_buffer;
            VkDeviceSize src_offset;
            VkDeviceSize dst_offset;
            VkDeviceSize size;
        } copy;
        
        struct {
            uint32_t dependency_count;
            const VkDependencyInfo* info;
        } barrier;
        
        struct {
            VkDescriptorSet set;
            uint32_t pipeline_layout;
        } bind_desc_set;
        
        struct {
            VkPipeline pipeline;
            VkPipelineLayout layout;
        } bind_pipeline;
    } args;
    
    /* Dependencies */
    struct mvgal_cmd_node** deps;
    size_t dep_count;
    size_t dep_capacity;
    
    /* Next node in list */
    struct mvgal_cmd_node* next;
    
    /* Vendor-specific emissions */
    void* vendor_data[MVGAL_MAX_GPUS];
} mvgal_cmd_node_t;

/* ------------------------------------------------------------------ */
/*  DAG Structure                                                       */
/* ------------------------------------------------------------------ */

typedef struct {
    mvgal_cmd_node_t* head;
    size_t node_count;
    uint32_t queue_family;
    uint32_t cmd_buffer_idx;
    bool primary; /* True if this is a primary command buffer */
} mvgal_cmd_dag_t;

/* ------------------------------------------------------------------ */
/*  DAG Construction                                                    */
/* ------------------------------------------------------------------ */

/**
 * @brief Create a new empty DAG
 * @return New DAG or NULL on failure
 */
mvgal_cmd_dag_t* mvgal_dag_create(void);

/**
 * @brief Destroy a DAG
 * @param dag DAG to destroy
 */
void mvgal_dag_destroy(mvgal_cmd_dag_t* dag);

/**
 * @brief Add a node to the DAG
 * @param dag DAG
 * @param type Command type
 * @return New node or NULL on failure
 */
mvgal_cmd_node_t* mvgal_dag_add_node(mvgal_cmd_dag_t* dag, mvgal_cmd_type_t type);

/**
 * @brief Add dependency between nodes
 * @param from Source node
 * @param to Target node (must execute after source)
 */
void mvgal_dag_add_dependency(mvgal_cmd_node_t* from, mvgal_cmd_node_t* to);

/* ------------------------------------------------------------------ */
/*  Command Recording Interceptions                                   */
/* ------------------------------------------------------------------ */

/**
 * @brief Record a draw command into the DAG
 * @param dag DAG to record into
 * @param vertex_count Number of vertices
 * @param instance_count Number of instances
 */
void mvgal_record_cmd_draw(mvgal_cmd_dag_t* dag, uint32_t vertex_count, uint32_t instance_count);

/**
 * @brief Record a dispatch command into the DAG
 * @param dag DAG to record into
 * @param group_x X workgroup size
 * @param group_y Y workgroup size
 * @param group_z Z workgroup size
 */
void mvgal_record_cmd_dispatch(mvgal_cmd_dag_t* dag, uint32_t group_x, uint32_t group_y, uint32_t group_z);

/**
 * @brief Record a barrier command into the DAG
 * @param dag DAG to record into
 * @param dependency_count Number of dependencies
 * @param info Dependency info
 */
void mvgal_record_cmd_barrier(mvgal_cmd_dag_t* dag, uint32_t dependency_count, const VkDependencyInfo* info);

/**
 * @brief Begin recording a command buffer to DAG
 * @param cmd_buf Original command buffer
 * @return New DAG or NULL on failure
 */
mvgal_cmd_dag_t* mvgal_cmd_dag_begin(VkCommandBuffer cmd_buf);


/**
 * @brief End recording a command buffer
 * @param cmd_buf Command buffer to end
 */
void mvgal_cmd_dag_end(VkCommandBuffer cmd_buf);

/* ------------------------------------------------------------------ */
/*  DAG Capture from Vulkan Command Buffer                              */
/* ------------------------------------------------------------------ */

/**
 * @brief Capture a Vulkan command buffer as a DAG
 * @param cmd Original command buffer
 * @param dag Output DAG
 * @return VK_SUCCESS on success
 */
VkResult mvgal_capture_command_buffer(VkCommandBuffer cmd, mvgal_cmd_dag_t** dag);

/* ------------------------------------------------------------------ */
/*  DAG Translation and Emission                                        */
/* ------------------------------------------------------------------ */

/**
 * @brief Translate DAG for a target vendor
 * @param dag Input DAG
 * @param vendor Target vendor
 * @return Translated DAG copy or NULL
 */
mvgal_cmd_dag_t* mvgal_translate_dag(mvgal_cmd_dag_t* dag, mvgal_vendor_t vendor);

/**
 * @brief Emit DAG to a Vulkan command buffer
 * @param dag DAG to emit
 * @param cmd Target command buffer
 * @return VK_SUCCESS on success
 */
VkResult mvgal_emit_dag(mvgal_cmd_dag_t* dag, VkCommandBuffer cmd);

#ifdef __cplusplus
}
#endif

#endif /* MVGAL_CMD_DAG_H */