#pragma once

#include <cstdint>
#include <vector>

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

const std::vector<const char*> DeviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };

class VulkanSwapChain
{
public:
	VulkanSwapChain(
		VkDevice							   Device,
		VkSurfaceKHR						   Surface,
		GLFWwindow*							   Window,
		uint32_t							   GraphicsFamily,
		uint32_t							   PresentFamily,
		const VkSurfaceCapabilitiesKHR&		   Capabilities,
		const std::vector<VkSurfaceFormatKHR>& Formats,
		const std::vector<VkPresentModeKHR>&   PresentModes
	);

	~VulkanSwapChain();

	VulkanSwapChain(const VulkanSwapChain&) = delete;
	VulkanSwapChain& operator=(const VulkanSwapChain&) = delete;

	void CreateSwapChain();
	void CreateImageViews();

	void Cleanup();

	VkImageView	   CreateImageView(VkImage Image, VkFormat Format, VkImageAspectFlags AspectFlags);
	VkSwapchainKHR GetSwapChain() { return SwapChain; }
	VkFormat	   GetSwapChainImageFormat() { return SwapChainImageFormat; }
	VkExtent2D	   GetSwapChainExtent() { return SwapChainExtent; }
	std::vector<VkImageView>& GetSwapChainImageViews() { return SwapChainImageViews; }
	size_t					  GetSwapChainImagesCount() { return SwapChainImages.size(); }

private:
	VkDevice						Device;
	VkSurfaceKHR					Surface;
	GLFWwindow*						Window;
	uint32_t						GraphicsFamily;
	uint32_t						PresentFamily;
	VkSurfaceCapabilitiesKHR		Capabilities;
	std::vector<VkSurfaceFormatKHR> Formats;
	std::vector<VkPresentModeKHR>	PresentModes;

	std::vector<VkImage>	 SwapChainImages;
	VkSwapchainKHR			 SwapChain = VK_NULL_HANDLE;
	VkFormat				 SwapChainImageFormat;
	VkExtent2D				 SwapChainExtent;
	std::vector<VkImageView> SwapChainImageViews;

	VkSurfaceFormatKHR
	ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& AvailableFormats);
	VkPresentModeKHR
			   ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& AvailablePresentModes);
	VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities);
};
