#pragma once

#include "VulkanCommandBuffers.h"
#include "VulkanFramebuffers.h"
#include "VulkanInstanceManager.h"
#include "VulkanDeviceManager.h"
#include "VulkanDebugManager.h"
#include "VulkanPipeline.h"
#include "VulkanRenderPass.h"
#include "VulkanSwapChain.h"
#include "VulkanVertexBuffer.h"

#include <cstdint>
#include <vector>
#include <vulkan/vulkan_core.h>

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

static const std::vector<const char*> ValidationLayers = {
	"VK_LAYER_KHRONOS_validation"
};

struct FVulkanConfig
{
	bool		bValidationEnabled = true;
	bool		bVerboseLogging = false;
	GLFWwindow* Window = nullptr;
	// std::vector<Vertex> Vertices;
};

static FVulkanConfig Config = {};

class VulkanContext
{
public:
	VulkanContext();
	~VulkanContext();

	VulkanInstanceManager InstanceManager;
	VulkanDebugManager	  DebugManager;
	VulkanDeviceManager	  DeviceManager;
	VulkanSwapChain		  SwapChain;
	VulkanPipeline		  GraphicsPipeline;
	VulkanRenderPass	  RenderPass;
	VulkanFramebuffers	  Framebuffers;
	VulkanVertexBuffer	  VertexBuffer;
	VulkanCommandBuffers  CommandBuffers;
	VkDescriptorPool	  ImGuiPool;

	void Initialize(FVulkanConfig& InConfig, const std::vector<Vertex>& InVertices);
	void Cleanup();

	void CreateSurface(GLFWwindow* Window);
	void CreateSyncObjects();
	void DrawFrame(bool bDrawImGui = false, uint32_t InVerticesSize = 0);
	void RecreateSwapChain();
	void InitImGui();
	void CleanupSwapChain();
	// void DrawFrame(ImDrawData* DrawData = nullptr);

	VkSurfaceKHR GetSurface() { return Surface; };

	void SetFramebufferResized(bool bResized) { bFramebufferResized = bResized; }

private:
	VkSurfaceKHR Surface = VK_NULL_HANDLE;

	std::vector<VkSemaphore> ImageAvailableSemaphores;
	std::vector<VkSemaphore> RenderFinishedSemaphores;
	std::vector<VkFence>	 InFlightFences;

	bool bFramebufferResized = false;
	bool bImGuiGlfwInitialized = false;
	bool bImGuiVulkanInitialized = false;

	const int MAX_FRAMES_IN_FLIGHT = 2;
	uint32_t  CurrentFrame = 0;
};
