#pragma once

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

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

struct QueueFamilyIndices
{
	std::optional<uint32_t> GraphicsFamily;
	std::optional<uint32_t> PresentFamily;

	bool IsComplete()
	{
		return GraphicsFamily.has_value() && PresentFamily.has_value();
	}
};

struct SwapChainSupportDetails
{
	VkSurfaceCapabilitiesKHR		Capabilities;
	std::vector<VkSurfaceFormatKHR> Formats;
	std::vector<VkPresentModeKHR>	PresentModes;
};

class VulkanDeviceManager
{
public:
	VulkanDeviceManager(
		VkInstance	 Instance,
		VkSurfaceKHR Surface,
		GLFWwindow*	 Window,
		bool		 bEnableValidationLayers);

	~VulkanDeviceManager();

	void Cleanup();

	void					PickPhysicalDevice();
	void					CreateLogicalDevice();
	SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device);

	VkDevice		   GetDevice() { return Device; }
	VkPhysicalDevice   GetPhysicalDevice() { return PhysicalDevice; }
	QueueFamilyIndices GetPhysicalQueueFamilies() { return PhysicalQueueFamilies; }
	VkQueue			   GetGraphicsQueue() { return GraphicsQueue; }
	VkQueue			   GetPresentQueue() { return PresentQueue; }

private:
	VkInstance	 Instance;
	VkSurfaceKHR Surface;
	GLFWwindow*	 Window;
	bool		 bEnableValidationLayers;

	VkDevice		   Device = VK_NULL_HANDLE;
	VkPhysicalDevice   PhysicalDevice = VK_NULL_HANDLE;
	VkQueue			   GraphicsQueue = VK_NULL_HANDLE;
	VkQueue			   PresentQueue = VK_NULL_HANDLE;
	QueueFamilyIndices PhysicalQueueFamilies;

	bool IsDeviceSuitable(VkPhysicalDevice Device);

	int RateDeviceSuitability(VkPhysicalDevice Device);

	bool CheckDeviceExtensionSupport(VkPhysicalDevice Device);

	QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice Device);
};
