/**
 * @file mvgal_unified_heap.h
 * @brief Unified VRAM Heap API for Cross-GPU Memory Management
 *
 * Multi-Vendor GPU Aggregation Layer for Linux
 *
 * This header provides unified virtual memory management across heterogeneous GPUs.
 */

#ifndef MVGAL_UNIFIED_HEAP_H
#define MVGAL_UNIFIED_HEAP_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "mvgal_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @addtogroup UnifiedMemory
 * @{
 */

/**
 * @brief Unified heap handle
 */
typedef struct mvgal_unified_heap *mvgal_unified_heap_handle_t;

/**
 * @brief Memory placement hint
 */
typedef enum {
    MVGAL_PLACEMENT_AUTO = 0,      /**< Automatic placement */
    MVGAL_PLACEMENT_VRAM = 1,      /**< Prefer VRAM */
    MVGAL_PLACEMENT_HOST = 2,      /**< Prefer host RAM */
    MVGAL_PLACEMENT_REPLICATED = 3, /**< Replicate to all GPUs */
    MVGAL_PLACEMENT_P2P = 4,      /**< Use P2P-capable placement */
} mvgal_placement_hint_t;

/**
 * @brief Memory access pattern hint
 */
typedef enum {
    MVGAL_ACCESS_STREAMING = 0,    /**< Streaming access */
    MVGAL_ACCESS_RANDOM = 1,       /**< Random access */
    MVGAL_ACCESS_SEQUENTIAL = 2,   /**< Sequential access */
} mvgal_access_hint_t;

/**
 * @brief Page fault handler callback
 */
typedef void (*mvgal_page_fault_cb_t)(void* user_data,
                                      uint64_t address,
                                      uint32_t gpu_index,
                                      size_t size);

/**
 * @brief Initialize unified heap
 * @param heap Heap handle (out)
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_unified_heap_init(mvgal_unified_heap_handle_t *heap);

/**
 * @brief Cleanup unified heap
 * @param heap Heap handle
 */
void mvgal_unified_heap_fini(mvgal_unified_heap_handle_t heap);

/**
 * @brief Allocate unified memory
 * @param heap Heap handle
 * @param size Size in bytes
 * @param placement Placement hint
 * @param access_hint Access pattern hint
 * @param ptr Pointer to allocation (out)
 * @return Allocation ID or 0 on failure
 */
uint64_t mvgal_unified_heap_allocate(mvgal_unified_heap_handle_t heap,
                                      size_t size,
                                      mvgal_placement_hint_t placement,
                                      mvgal_access_hint_t access_hint,
                                      void **ptr);

/**
 * @brief Free unified memory
 * @param heap Heap handle
 * @param alloc_id Allocation ID
 */
void mvgal_unified_heap_free(mvgal_unified_heap_handle_t heap, uint64_t alloc_id);

/**
 * @brief Get GPU address for allocation
 * @param heap Heap handle
 * @param alloc_id Allocation ID
 * @param gpu_index GPU index
 * @return GPU address or 0 on failure
 */
uint64_t mvgal_unified_heap_get_gpu_address(mvgal_unified_heap_handle_t heap,
                                             uint64_t alloc_id,
                                             uint32_t gpu_index);

/**
 * @brief Migrate allocation to another GPU
 * @param heap Heap handle
 * @param alloc_id Allocation ID
 * @param target_gpu Target GPU index
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_unified_heap_migrate(mvgal_unified_heap_handle_t heap,
                                           uint64_t alloc_id,
                                           uint32_t target_gpu);

/**
 * @brief Replicate allocation to multiple GPUs
 * @param heap Heap handle
 * @param alloc_id Allocation ID
 * @param gpu_indices Array of GPU indices
 * @param gpu_count Number of GPUs
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_unified_heap_replicate(mvgal_unified_heap_handle_t heap,
                                           uint64_t alloc_id,
                                           const uint32_t *gpu_indices,
                                           uint32_t gpu_count);

/**
 * @brief Register page fault handler
 * @param heap Heap handle
 * @param callback Page fault callback
 * @param user_data User data for callback
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_unified_heap_set_page_fault_handler(
    mvgal_unified_heap_handle_t heap,
    mvgal_page_fault_cb_t callback,
    void *user_data);

/**
 * @brief Query heap statistics
 * @param heap Heap handle
 * @param total_bytes Total allocated bytes (out)
 * @param cross_gpu_transfers Cross-GPU transfer count (out)
 * @param page_faults Page fault count (out)
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_unified_heap_get_stats(mvgal_unified_heap_handle_t heap,
                                           uint64_t *total_bytes,
                                           uint64_t *cross_gpu_transfers,
                                           uint64_t *page_faults);

/**
 * @brief Check P2P support between GPUs
 * @param gpu_a GPU A index
 * @param gpu_b GPU B index
 * @return true if P2P is supported
 */
bool mvgal_unified_heap_p2p_supported(uint32_t gpu_a, uint32_t gpu_b);

/**
 * @brief Get peer access mask for a GPU
 * @param gpu_index GPU index
 * @return Bitmask of GPUs that can be accessed via P2P
 */
uint64_t mvgal_unified_heap_get_peer_mask(uint32_t gpu_index);

/** @} */ // end of UnifiedMemory

#ifdef __cplusplus
}
#endif

#endif /* MVGAL_UNIFIED_HEAP_H */