#include "VulkanCommandBuffers.h"

#include "imgui.h"
#include "imgui_impl_vulkan.h"
#include "utilities/Logger.h"
#include <cstdint>
#include <vulkan/vulkan_core.h>

void VulkanCommandBuffers::Initialize(
	VkDevice	 InDevice,
	VkRenderPass InRenderPass)
{
	Device = InDevice;
	RenderPass = InRenderPass;
}

void VulkanCommandBuffers::Cleanup()
{
	vkDestroyCommandPool(Device, CommandPool, nullptr);
}

void VulkanCommandBuffers::CreateCommandPool(std::optional<uint32_t> GraphicsFamily)
{
	VkCommandPoolCreateInfo PoolInfo{};
	PoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
	PoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
	PoolInfo.queueFamilyIndex = GraphicsFamily.value();

	if (vkCreateCommandPool(Device, &PoolInfo, nullptr, &CommandPool) != VK_SUCCESS)
	{
		Log::Error("Failed to create command pool!");
	}
	else
	{
		Log::Info("Successfully created command pool");
	}
}

void VulkanCommandBuffers::CreateCommandBuffers(int FramesInFlight)
{
	CommandBuffers.resize(FramesInFlight);
	VkCommandBufferAllocateInfo AllocateInfo{};
	AllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
	AllocateInfo.commandPool = CommandPool;
	AllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
	AllocateInfo.commandBufferCount = (uint32_t)CommandBuffers.size();

	if (vkAllocateCommandBuffers(Device, &AllocateInfo, CommandBuffers.data()) != VK_SUCCESS)
	{
		Log::Error("Failed to allocate command buffers!");
	}
	else
	{
		Log::Info("Successfully allocated command buffers.");
	}
}

void VulkanCommandBuffers::RecordCommandBuffer(FRecordCommandBuffersParams& Params)
{
	VkCommandBufferBeginInfo BeginInfo{};
	BeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
	BeginInfo.flags = 0;
	BeginInfo.pInheritanceInfo = nullptr;

	if (vkBeginCommandBuffer(Params.InCommandBuffer, &BeginInfo) != VK_SUCCESS)
	{
		Log::Error("Failed to begin recording command buffer!");
	}
	else
	{
		// Log::Info("Successfully began recording command buffers.");
	}

	VkRenderPassBeginInfo RenderPassInfo{};
	RenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
	RenderPassInfo.renderPass = RenderPass;
	RenderPassInfo.framebuffer = Params.SwapChainFramebuffers[Params.ImageIndex];
	RenderPassInfo.renderArea.offset = { 0, 0 };
	RenderPassInfo.renderArea.extent = { Params.SwapChainExtent };

	VkClearValue ClearColor = { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
	RenderPassInfo.clearValueCount = 1;
	RenderPassInfo.pClearValues = &ClearColor;

	vkCmdBeginRenderPass(Params.InCommandBuffer, &RenderPassInfo, VK_SUBPASS_CONTENTS_INLINE);

	vkCmdBindPipeline(Params.InCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, Params.GraphicsPipeline);

	VkViewport Viewport{};
	Viewport.x = 0.0f;
	Viewport.y = 0.0f;
	Viewport.width = static_cast<float>(Params.SwapChainExtent.width);
	Viewport.height = static_cast<float>(Params.SwapChainExtent.height);
	Viewport.minDepth = 0.0f;
	Viewport.maxDepth = 1.0f;
	vkCmdSetViewport(Params.InCommandBuffer, 0, 1, &Viewport);

	VkRect2D Scissor{};
	Scissor.offset = { 0, 0 };
	Scissor.extent = Params.SwapChainExtent;
	vkCmdSetScissor(Params.InCommandBuffer, 0, 1, &Scissor);

	VkBuffer	 VertexBuffers[] = { Params.InVertexBuffer };
	VkDeviceSize Offsets[] = { 0 };
	vkCmdBindVertexBuffers(Params.InCommandBuffer, 0, 1, VertexBuffers, Offsets);
	vkCmdBindIndexBuffer(Params.InCommandBuffer, Params.InIndexBuffer, 0, VK_INDEX_TYPE_UINT16);

	vkCmdBindDescriptorSets(Params.InCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, Params.PipelineLayout, 0, 1, &Params.DescriptorSet, 0, nullptr);

	// vkCmdDraw(Params.InCommandBuffer, static_cast<uint32_t>(Params.InVerticesSize), 1, 0, 0);
	vkCmdDrawIndexed(Params.InCommandBuffer, static_cast<uint32_t>(Params.InIndexSize), 1, 0, 0, 0);

	if (Params.bDrawImGui)
	{
		ImGui::Render();
		ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), Params.InCommandBuffer);
	}

	vkCmdEndRenderPass(Params.InCommandBuffer);

	if (vkEndCommandBuffer(Params.InCommandBuffer) != VK_SUCCESS)
	{
		Log::Error("Failed to record command buffer!");
	}
	else
	{
		// Log::Info("Successfully recorded command buffer.");
	}
}
