#ifndef VULKAN_BUFFERS_H
#define VULKAN_BUFFERS_H

#include <stdint.h>
#include <vma/vk_mem_alloc.h>

#include "graphics_context.h"
#include "utilities/commons.h"
#include "vulkan_commons.h"

/**
 * @brief Create buffers needed by vulkan pipeline
 *
 * @param context Graphics context handle
 * @return rse_err_t RSE_ERROR_NO_ERROR on success
 */
rse_err_t create_buffers(struct graphics_context_t* context);

/**
 * @brief Create a Uniform Buffers
 *
 * @param context Graphics context handle
 * @param buffer Buffer handle to hold new buffer
 * @return rse_err_t RSE_ERROR_NO_ERROR on success.
 */
rse_err_t buffer_create_uniform(struct graphics_context_t* context, struct vulkan_buffer_t* buffer,
                                VkDeviceSize buffer_size);

/**
 * @brief Add vertices and indices to vulkan buffers
 *
 * @param vertices_count Number of provided vertices
 * @param vertices Vertices to add
 * @param indices_count Number of provided indices
 * @param indices Indices to add
 * @return rse_err_t RSE_ERROR_NO_ERROR on success
 */
rse_err_t add_vertices(struct graphics_context_t* context, uint16_t mesh_id, size_t vertices_count,
                       const struct vertex_t* vertices, size_t indices_count, const uint16_t* indices);

/**
 * @brief Add instance data to vulkan buffers
 *
 * @param mesh_id Mesh ID
 * @param instance_data Instance data
 * @return rse_err_t RSE_ERROR_NO_ERROR on success
 */
rse_err_t mesh_add_instance(struct graphics_context_t* context, uint32_t mesh_id,
                                struct instance_data_t* instance_data);

/**
 * @brief Record commands for given image index
 *
 * @param vulkan_state
 * @param imageIndex
 * @return rse_err_t RSE_ERROR_NO_ERROR on success
 */
rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t imageIndex);

/**
 * @brief Reset command buffer for current frame.
 *
 * @param vulkan_state
 */
void reset_command_buffer(struct graphics_context_t* context);

/**
 * @brief Destroy ALL previously allocated buffers
 *
 * @param vulkan_state
 */
void destroy_buffers(struct graphics_context_t* context);

/**
 * @brief Helper function. Creates a buffer object
 *
 * @param size Size of the target buffer
 * @param buffer_usage Buffer usage flags
 * @param memory_usage memory usage flags (mostly VMA_MEMORY_USAGE_AUTO)
 * @param allocation_flags VMA allocation flags
 * @param buffer Buffer, that will be allocated
 * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
 *             VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
 */
rse_err_t create_buffer(struct graphics_context_t* context, const VkDeviceSize size, VkBufferUsageFlags buffer_usage,
                        VmaMemoryUsage memory_usage, const VmaAllocationCreateFlags allocation_flags,
                        struct vulkan_buffer_t* buffer);

/**
 * @brief Update vulkan buffers. Instance data and all that. This must be called before running vulkan application
 *
 * @param context Graphics context
 * @return rse_err_t RSE_ERROR_NO_ERROR on success
 */
rse_err_t buffers_update(struct graphics_context_t* context);

/**
 * @brief Destroy provided buffer
 *
 * @param buffer buffer to destroy
 */
void destroy_buffer(struct graphics_context_t* context, struct vulkan_buffer_t* buffer);

#endif /* VULKAN_BUFFERS_H */
