#pragma once
#include <deerith/core/log.h>
#include <deerith/graphics/graphics.h>

#include <optional>
#include <vector>

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

#define ACTIVE_VALIDATION_LAYER true

class GLFWwindow;

namespace deerith {
	namespace graphics {
		struct QueueFamilyIndices {
			std::optional<uint32_t> graphics_family;
			std::optional<uint32_t> present_family;

			inline bool is_complete() const {
				return graphics_family.has_value() && present_family.has_value();
			}
		};

		struct SwapChainSupportDetails {
			VkSurfaceCapabilitiesKHR capabilities;
			std::vector<VkSurfaceFormatKHR> formats;
			std::vector<VkPresentModeKHR> present_modes;
		};

		extern GraphicsConfig graphics_config;
		extern GLFWwindow* window;

		// Vulkan Specific
		extern VkInstance instance;
		extern const std::vector<const char*> validation_layers;
		extern const std::vector<const char*> device_extensions;
		extern VkPhysicalDevice physical_device;
		extern QueueFamilyIndices queue_family_indices;
		extern SwapChainSupportDetails swap_chain_support_details;
		extern VkDevice device;
		extern VkQueue graphics_queue;
		extern VkQueue pressent_queue;
		extern VkSurfaceKHR surface;
		extern VkSwapchainKHR swap_chain;
		extern std::vector<VkImage> swap_chain_images;
		extern VkFormat swap_chain_image_format;
		extern VkExtent2D swap_chain_extent;
		extern std::vector<VkImageView> swap_chain_image_views;
		extern VkPipelineLayout pipeline_layout;
		extern VkRenderPass render_pass;
		extern VkPipeline graphics_pipeline;
		extern std::vector<VkFramebuffer> swap_chain_frame_buffers;
		extern VkCommandPool command_pool;
		extern VkCommandBuffer command_buffer;

		extern VkSemaphore image_available_semaphore;
		extern VkSemaphore render_finished_semaphore;
		extern VkFence in_flight_fence;

		void init_glfw();
		void shutdown_glfw();

		void init_vulkan();
		void shutdown_vulkan();

		void create_vulkan_instance();
		void create_vulkan_validation_layer();
		void create_vulkan_surface();
		void create_vulkan_phisical_device();
		void create_vulkan_logical_device();
		void create_vulkan_swap_chain();
		void create_vulkan_image_view();
		void create_vulkan_render_pass();
		void create_vulkan_graphics_pipeline();
		void create_vulkan_frame_buffer();
		void create_vulkan_command_buffer();
		void create_vulkan_sync_objects();

		void vulkan_test_loop();

		QueueFamilyIndices find_queue_families(VkPhysicalDevice device);
		SwapChainSupportDetails query_swap_chain_support(VkPhysicalDevice device);
		void record_command_buffer(VkCommandBuffer commandBuffer, uint32_t imageIndex);

	} // namespace graphics
} // namespace deerith