/**
 * @file graphics_context.h
 * @author Piotr Krygier (piotrkrygier@everyonencancode.xyz)
 * @brief Graphics context for Red Scarf Engine
 * @version 0.1
 * @date 2024-05-22
 *
 * @copyright Copyright (c) 2024
 *
 */

#ifndef GRAPHICS_CONTEXT_H
#define GRAPHICS_CONTEXT_H

#include <SDL3/SDL.h>
#include <SDL3/SDL_render.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <vulkan/vulkan.h>

#include "utilities/entity.h"
#include "utilities/vector.h"
#include "vma/vk_mem_alloc.h"
#include "vulkan/vulkan_core.h"
#include "vulkan_commons.h"

#define MAX_MESH_NUMBER 256U
/* FIXME: This is the total number of instances * meshes. It shouldn't be so low */
#define MAX_INSTANCE_NUMBER (MAX_MESH_NUMBER * 256U)

#define SWAPCHAIN_IMAGE_COUNT (3U)

/**
 * @brief Maximum number of textures that can be loaded
 *
 */
#define RSE_MAX_IMAGE_COUNT 256

#define MAX_VULKAN_BUFFERS_COUNT (32U)

#define MAX_PIPELINE_COUNT 16
#define MAX_CREATE_INFOS (32U)
#define MAX_SHADER_STAGES 12U
#define MAX_SHADER_MODULES_COUNT (128U)
#define MAX_VERTEX_BINDINGS_COUNT (32U)
#define MAX_SHADER_ATTRIBUTES_COUNT (32U)
#define MAX_DYNAMIC_STATES_COUNT (32U)
#define MAX_PUSH_CONSTANTS_COUNT (32U)

#define DESCRIPTOR_MAX_SETS (32U)
#define DESCRIPTOR_TYPE_ID_MAX_ENUM (21U)
#define RENDERER_MAX_COUNT MAX_PIPELINE_COUNT

#define FONT_CHARACTERS_COUNT (94U)
#define FONTS_MAX_COUNT (32U)

struct graphics_context_t;

enum QUEUE_FAMILY_INDEX {
    QUEUE_FAMILY_INDEX_GRAPHICS,
    QUEUE_FAMILY_INDEX_PRESENTATION,
    QUEUE_FAMILY_INDEX_LAST_INDEX,
};

enum RENDER_TARGET {
    RENDER_TARGET_3D,
    RENDER_TARGET_2D,
    RENDER_TARGET_COUNT
};

/**
 * @brief Represents data within vertex or instance buffer.
 *
 */
struct buffer_data_t
{
    size_t count;
    size_t buffer_offset;
};

struct vulkan_buffers_t {
    size_t vulkan_buffers_count;
    struct vulkan_buffer_t vulkan_buffers[MAX_VULKAN_BUFFERS_COUNT];
};

/**
 * @brief Wrapper for Vulkan buffer. Holds allocation data;
 *
 */
struct vulkan_image_t
{
    uint8_t id_taken;
    size_t allocated_size;
    VkImage image;
    VkImageView image_view;
    VmaAllocation allocation;
    VmaAllocationInfo allocation_info;
};

RSE_VECTOR_DEFINE(instance_vector_t, struct instance_data_t);
/**
 * @brief Mesh data, with unique id and dynamic arrays holding vertices and indices.
 * One mesh can have multiple instances.
 *
 */
struct mesh_t
{
    size_t vertex_count;
    bool is_dirty;
    size_t entities_count;
    entity_t* entities; /* Which entities are connected to  this mesh */
    size_t index_count;
    size_t instances_count;
    struct instance_vector_t instances_data;
};

struct shader_modules_t
{
    uint16_t shader_modules_count;
    VkShaderModule shader_modules[MAX_SHADER_MODULES_COUNT];
    VkShaderStageFlagBits shaders_stages[MAX_SHADER_MODULES_COUNT];
};

struct required_dynamic_states_t {
    size_t dynamic_states_count;
    VkDynamicState dynamic_states[MAX_DYNAMIC_STATES_COUNT];
};

struct push_constant_ranges_t
{
    size_t push_constant_ranges_count;
    VkPushConstantRange  push_constant_ranges[MAX_PUSH_CONSTANTS_COUNT];
};

struct pipeline_infos_t
{
    size_t pipeline_create_infos_count;
    VkGraphicsPipelineCreateInfo create_infos[MAX_CREATE_INFOS];
};

struct pipeline_t
{
    VkPipeline pipeline;
    uint8_t id;
    /* Shader stages */
    size_t shader_stages_count;
    VkPipelineShaderStageCreateInfo shader_stages[MAX_SHADER_STAGES];
    /* Input assembly */
    VkPipelineInputAssemblyStateCreateInfo input_assembly;
    /* Viewport state */
    VkPipelineViewportStateCreateInfo viewport_state;
    /* Rasterizer */
    VkPipelineRasterizationStateCreateInfo rasterizer;
    /* Multisampling */
    VkPipelineMultisampleStateCreateInfo multisampling;
    /* Color blending */
    VkPipelineColorBlendAttachmentState color_blend_attachment;
    VkPipelineColorBlendStateCreateInfo color_blending;
    /* Depth stencil */
    VkPipelineDepthStencilStateCreateInfo depth_stencil;
    VkPipelineLayout pipeline_layout;
    size_t vertex_bindings_count;
    VkVertexInputBindingDescription vertex_bindings[MAX_VERTEX_BINDINGS_COUNT];
    size_t shader_attributes_count;
    VkVertexInputAttributeDescription shader_attributes[MAX_SHADER_ATTRIBUTES_COUNT];
    size_t dynamic_states_count;
    VkDynamicState dynamic_states[MAX_DYNAMIC_STATES_COUNT];
    struct push_constant_ranges_t push_constant_ranges;
    struct required_dynamic_states_t required_dynamic_states;
    struct descriptor_set_handle_t* descriptor_sets;
};

struct pipeline_internal_t
{
    rse_id_t descriptor_set_ids[MAX_PIPELINE_COUNT];
    size_t pipelines_count;
    size_t pipeline_layouts_count;
    VkPipeline pipelines[MAX_PIPELINE_COUNT];
    VkPipelineLayout pipeline_layouts[MAX_PIPELINE_COUNT];
};

struct descriptor_data_t
{
    uint32_t pool_sizes_count;
    uint32_t descriptor_sets_count;
    VkDescriptorPool descriptor_pool;
    VkDescriptorPoolSize pool_sizes[DESCRIPTOR_TYPE_ID_MAX_ENUM];
    VkDescriptorSet descriptor_sets[DESCRIPTOR_MAX_SETS];
    VkDescriptorSetLayout set_layouts[DESCRIPTOR_MAX_SETS];
};

struct descriptor_set_layout_bindings_t
{
    VkDescriptorSetLayoutBinding layout_bindings[DESCRIPTOR_MAX_SETS];
    uint32_t layout_bindings_count;
};

struct render_target_t
{
    struct vulkan_buffer_t vertex_buffer;
    struct vulkan_buffer_t index_buffer;
    size_t instances_data_size;
    struct vulkan_buffer_t instance_buffer;
    struct vulkan_buffer_t draw_indirect_command_buffer;
};

struct swapchain_data_t
{
    VkSwapchainKHR swapchain;
    VkImageView swapchain_image_views[SWAPCHAIN_IMAGE_COUNT];
    VkExtent2D swapchain_extent;
    VkFramebuffer swapchain_framebuffers[SWAPCHAIN_IMAGE_COUNT];
    VkImage swapchain_images[SWAPCHAIN_IMAGE_COUNT];
};

struct vulkan_handles
{
    VkSampler sampler;
    VkPhysicalDevice physical_device;
    VkDevice device;
    VmaAllocator allocator;
    VkSurfaceKHR surface;
    VkInstance instance;
    VkQueue graphics_queue;
    VkQueue present_queue;
    VkCommandPool command_pool;
    VkCommandBuffer command_buffers[SWAP_BUFFER_COUNT];
    VkRenderPass render_pass;
    VkSemaphore image_available_semaphores[SWAP_BUFFER_COUNT];
    VkSemaphore render_finished_semaphores[SWAP_BUFFER_COUNT];
    VkFence in_flight_fences[SWAP_BUFFER_COUNT];
#ifndef NDEBUG
    VkDebugUtilsMessengerEXT debug_messenger;
#endif // !NDEBUG
};

struct mesh_data_t {
    uint32_t mesh_count;
    struct mesh_t mesh_bucket[MAX_MESH_NUMBER];
};

struct debug_overlay_t
{
    rse_id_t texture_id;
    uint32_t* pixels;
    size_t pixels_size;
    struct vulkan_image_t image_handle;
    VkSampler sampler;
};

typedef rse_err_t(*renderer_function_t)(struct graphics_context_t* context, rse_id_t renderer_id);

struct renderer_t {
    renderer_function_t render_function;
};

struct renderer_data_t {
    size_t renderers_count;
    struct renderer_t renderers[RENDERER_MAX_COUNT];
};

struct font_character_data_t {
    rse_id_t mesh_id;
    rse_id_t texture_id;
};

struct sized_font_data_t {
    uint8_t font_size;
    struct font_character_data_t font_characters[FONT_CHARACTERS_COUNT];
};

struct fonts_data_t {
    struct sized_font_data_t fonts[FONTS_MAX_COUNT];
};

struct graphics_context_t
{
    bool is_framebuffer_resized;
    uint32_t queue_family_indices[QUEUE_FAMILY_INDEX_LAST_INDEX];
    uint32_t current_frame;
    uint32_t swapchain_images_count;
    SDL_Window* window_handle;
    struct mvp_data_t mvp_data;
    struct renderer_data_t renderer_data;
    struct debug_overlay_t debug_overlay;
    struct vulkan_handles vulkan_handles;
    struct swapchain_data_t swapchain_data;
    struct descriptor_data_t descriptor_data;
    struct pipeline_internal_t pipelines_data;
    struct render_target_t render_targets[RENDER_TARGET_COUNT];
    struct vulkan_buffers_t uniform_buffers;
    struct vulkan_image_t texture_images[RSE_MAX_IMAGE_COUNT];
    struct vulkan_image_t depth_image;
    struct vulkan_image_t color_image;
    struct shader_modules_t shader_modules;
    struct mesh_data_t mesh_data;
    struct fonts_data_t fonts_data;
};

#endif /* GRAPHICS_CONTEXT_H */
