#ifndef RT_VK_DEVICE_H
#define RT_VK_DEVICE_H

#include <volk/volk.h>
#include <runtime/runtime.h>
#include <renderer/renderer.h>
#include <renderer/backend_api.h>

#include "physical_resource_manager.h"
#include "bindless_registry.h"

#ifdef _WIN32
struct HINSTANCE__;
struct HWND__;
#elif defined(RT_USE_XLIB)
struct _XDisplay;
#endif

typedef struct {
#ifdef _WIN32
    struct HINSTANCE__ *hInstance;
    struct HWND__ *hWnd;
#elif defined(RT_USE_XLIB)
    struct _XDisplay *display;
    unsigned long window;
#endif
} rt_vk_native_window;


typedef struct {
    VkSemaphore render_finished;
    VkSemaphore image_available;
    VkSemaphore swapchain_transitioned;
} rt_vk_frame_data;

typedef struct rt_vk_device {
    /* *** Vulkan objects *** */
    VkInstance instance;
    VkDevice device;
    VkPhysicalDevice phys_device;
    VkAllocationCallbacks *alloc_cb;
    VkSurfaceKHR surface;

    /* *** Queues *** */
    uint32_t graphics_family;
    uint32_t compute_family;
    uint32_t transfer_family;
    uint32_t present_family;
    uint32_t unique_families[4];
    uint32_t unique_family_count;
    VkQueue graphics_queue;
    VkQueue compute_queue;
    VkQueue transfer_queue;
    VkQueue present_queue;


    /* *** Properties and features *** */
    VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props;
    VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features;
    VkPhysicalDeviceFeatures phys_device_features;
    VkPhysicalDeviceProperties phys_device_props;

    /* *** Per frame data *** */
    uint32_t max_frames_in_flight;
    rt_vk_frame_data frames[3];
    uint32_t current_frame_id;

    /* *** Windowing system *** */
    rt_vk_native_window native_window;
    VkSwapchainKHR swapchain;
    VkImage swapchain_images[4];
    VkImageView swapchain_image_views[4];
    uint32_t swapchain_image_count;

    /* *** Subsystems *** */
    rt_vk_physical_resource_manager phys_res_mgr;
    rt_vk_bindless_registry bindless_registry;

    /* *** Debug utils *** */
#ifdef RT_DEBUG
    VkDebugUtilsMessengerEXT messenger;
#endif
} rt_vk_device;

typedef struct {
    rt_result result;
    rt_vk_device device;
} rt_create_vk_device_result;

rt_create_vk_device_result rtCreateVkDevice(const rt_renderer_window_info *info);

void rtDestroyVkDevice(rt_vk_device *dev);

/* rt_render_device_i functions */
rt_physical_resource_manager_i rtVkDevGetPhysicalResourceManager(void *o);
rt_result rtVkDevSubmitCommandList(void *o, rt_render_command_list *list);

#endif
