/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "UiRenderer.hpp"
#include "Context.hpp"
#include "Base/UI/IVulkanWindow.hpp"
#include <array>
#include <imgui_impl_vulkan.h>
#if __has_include("GLFW/glfw3.h")
#include <imgui_impl_glfw.h>
#define GLFW_AVAILABLE
#else
#include "Host/ImGuiImplOpenVulkano.hpp"
#endif

namespace OpenVulkano::Vulkan
{
	void UiRenderer::Init(Context* context)
	{
		device = context->device->device;
		uiRenderPass.Init(context->device.get(), &context->swapChain, false, true);
		constexpr vk::DescriptorPoolSize sizeInfo[] = {
				{ vk::DescriptorType::eSampler, 1000 },
				{ vk::DescriptorType::eCombinedImageSampler, 1000 },
				{ vk::DescriptorType::eSampledImage, 1000 },
				{ vk::DescriptorType::eStorageImage, 1000 },
				{ vk::DescriptorType::eUniformTexelBuffer, 1000 },
				{ vk::DescriptorType::eStorageTexelBuffer, 1000 },
				{ vk::DescriptorType::eUniformBuffer, 1000 },
				{ vk::DescriptorType::eStorageBuffer, 1000 },
				{ vk::DescriptorType::eUniformBufferDynamic, 1000 },
				{ vk::DescriptorType::eStorageBufferDynamic, 1000 },
				{ vk::DescriptorType::eInputAttachment, 1000 }
		};
		vk::DescriptorPoolCreateInfo poolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, 1000, std::size(sizeInfo), sizeInfo);

		descriptorPool = context->device->device.createDescriptorPool(poolCreateInfo);

		ImGui_ImplVulkan_InitInfo vkInfo{};

		vkInfo.Instance = context->instance;
		vkInfo.PhysicalDevice = context->device->physicalDevice;
		vkInfo.Device = context->device->device;
		vkInfo.QueueFamily = context->device->queueIndices.GetGraphics();
		vkInfo.Queue = context->device->graphicsQueue;
		//vkInfo.PipelineCache = ;
		vkInfo.DescriptorPool = descriptorPool;
		vkInfo.Subpass = 0;
		vkInfo.MinImageCount = context->swapChain.GetImageCount();
		vkInfo.ImageCount = context->swapChain.GetImageCount();
		vkInfo.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
		vkInfo.UseDynamicRendering = false;

		ImGui::CreateContext();
		ImGuiIO& io = ImGui::GetIO(); (void)io;
		io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
		io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
		io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;

		ImGui_ImplVulkan_Init(&vkInfo, uiRenderPass.renderPass);
		window = context->window;
#ifdef GLFW_AVAILABLE
		ImGui_ImplGlfw_InitForVulkan((GLFWwindow*)window->GetNativeWindowHandle(), true);
#else
		ImGuiImplOpenVulkano::INSTANCE.Init(window);
#endif

		uiInitialized = true;
		if (ui) ui->Init();
	}

	void UiRenderer::Close()
	{
		uiInitialized = false;
#ifdef GLFW_AVAILABLE
		if (!window->WindowHasBeenDestroyed())
		{
			ImGui_ImplGlfw_Shutdown();
		}
#else
		ImGuiImplOpenVulkano::INSTANCE.Close();
#endif
		ImGui_ImplVulkan_Shutdown();
		device.destroy(descriptorPool);
		uiRenderPass.Close();
	}

	void UiRenderer::BeginUiFrame() const
	{
		ImGui_ImplVulkan_NewFrame();
#ifdef GLFW_AVAILABLE
		ImGui_ImplGlfw_NewFrame();
#else
		ImGuiImplOpenVulkano::INSTANCE.NewFrame();
#endif
		ImGui::NewFrame();
	}

	void UiRenderer::DrawUiFrame(vk::CommandBuffer& cmdBuffer)
	{
		if (!ui) return;
		BeginUiFrame();

		ui->Render();

		ImGui::Render();
		uiRenderPass.Begin(cmdBuffer, true);
		ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuffer);
		uiRenderPass.End(cmdBuffer);
	}

	void UiRenderer::SetActiveUi(Scene::UI::Ui* ui)
	{
		this->ui = ui;
		if (ui && uiInitialized) ui->Init();
	}
}
