/**
 * @file pipeline_builder.h
 * @author Piotr Krygier (everyonecancode@gmail.com)
 * @brief Builder for vulkan pipeline
 * @version 0.1
 * @date 2024-03-01
 *
 * @copyright Copyright (c) 2024
 *
 */

#ifndef PIPELINE_BUILDER_H
#define PIPELINE_BUILDER_H

#include <stdint.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h>

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

rse_err_t shader_create_module(struct graphics_context_t* context,
                               rse_id_t* shader_module_id,
                               const char* shader_path,
                               const VkShaderStageFlagBits shader_stage);

/**
 * @brief Initialize pipeline builder
 *
 * @param[out] pipeline Pipeline to initialize. Must not be NULL
 * @return RSE_SUCCESS on success, error code otherwise
 */
rse_err_t pipeline_builder_init(struct pipeline_t* pipeline);

/**
 * @brief Add shader stages to pipeline
 *
 * @param[in] context Graphics context handle
 * @param[in] pipeline Pipeline to build
 * @param[in] shader_id ID of the shader we want to add to pipeline
 * @return RSE_SUCCESS on success, error code otherwise
 */
rse_err_t pipeline_add_shader_stage(struct graphics_context_t* context,
                                    struct pipeline_t* pipeline,
                                    const rse_id_t shader_id);

/**
 * @brief Add vertex input binding to pipeline
 *
 * @param[in] pipeline Pipeline to build
 * @param[in] binding Binding point for vertex data
 * @param[in] stride Stride between vertex data elements in bytes
 * @param[in] input_rate Input rate for vertex data
 * @return RSE_SUCCESS on success, error code otherwise
 */
rse_err_t pipeline_add_vertex_input_binding(struct pipeline_t* pipeline,
                                            const uint8_t binding,
                                            const uint8_t stride,
                                            const VkVertexInputRate input_rate);

/**
 * @brief Add vertex attribute to shader in pipeline
 *
 * @param[in] pipeline Pipeline to build
 * @param[in] binding Binding point for vertex data
 * @param[in] location Location of the attribute in shader
 * @param[in] format Format of the attribute
 * @param[in] offset Offset of the attribute in bytes
 * @return RSE_SUCCESS on success, error code otherwise
 */
rse_err_t pipeline_add_vertex_input_attribute(struct pipeline_t* pipeline,
                                              const uint8_t binding,
                                              const uint8_t location,
                                              const VkFormat format,
                                              const uint8_t offset);

/**
 * @brief Add dynamic state to pipeline
 *
 * @param[in] pipeline Pipeline to build
 * @param[in] dynamic_state Dynamic state to add
 * @return RSE_SUCCESS on success, error code otherwise
 */
rse_err_t pipeline_add_dynamic_state(struct pipeline_t* pipeline, const VkDynamicState dynamic_state);

/**
 * @brief Create a Pipeline Layout
 *
 * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
 *             VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED
 */
rse_err_t pipeline_add_descriptor_sets(struct graphics_context_t* context,
                                       struct pipeline_t* pipeline,
                                       uint32_t descriptor_set_id);

/**
 * @brief Add push constants to pipeline
 *
 * @return RSE_ERROR_NO_ERROR on success
 *
 */
rse_err_t pipeline_add_push_constants(struct pipeline_t* pipeline,
                                       VkShaderStageFlagBits shader_stage,
                                       uint32_t offset,
                                       uint32_t size);

/**
 * @brief Build pipeline from added components. This function should be called after adding all necessary components.
 * After call, pipeline is ready to be used and all added components are cleared, ready for next pipeline to be built.
 *
 * param[in/out] context Graphics context handle
 * @param[in] pipeline Pipelines list to build
 * @param[in] descriptor_set_handle Filled handle with descriptor sets
 * @return RSE_SUCCESS on success, error code otherwise
 */
rse_err_t pipelines_build(struct graphics_context_t* context, struct pipeline_infos_t* pipelines);

/**
 * @brief Add pipeline to list of pipelines
 *
 * @param[in] context Graphics context handle
 * @param[in] pipeline Pipeline to add
 * @param[out] pipeline_infos Array of pipelines infos, where new info should be added
 * @return RSE_SUCCESS on success, error code otherwise
 */
rse_err_t pipeline_add(const struct graphics_context_t* context,
                       struct pipeline_t* pipeline,
                       struct pipeline_infos_t* pipelines_infos);

/**
 * @brief Destroy all pipelines
 *
 * @param[in] context Graphics context handle
 */
void destroy_pipelines(struct graphics_context_t* context);

#endif /* PIPELINE_BUILDER_H */
