#include "imguiManager.h"
#include "application_class.h"
#include "stats.h"

static fps_limiter fpsLimiter(60.0f);

imguiManager::imguiManager()
{
	io = nullptr;
	m_frameTimeHistoryIndex = 0;

	current_fps_ = 0;
	min_fps_ = 0;
	max_fps_ = 0;
	draw_calls_ = 0;
	total_vertex_count_ = 0;
	total_triangle_count_ = 0;
	visible_triangle_count_ = 0;
	current_frame_time_ = 0;

	showObjectWindow = false;
	showTerrainWindow = false;
	showLightWindow = false;
	showOldSceneWindow = false;
	showEngineSettingsWindow = false;
	showLogWindow = false;
	showStatsWindow = false;
	show_inspector_window_ = false;
    
	// Initialiser l'historique des frametimes � z�ro
	for (int i = 0; i < FRAME_HISTORY_COUNT; i++)
	{
		m_frameTimeHistory[i] = 0.0f;
	}

	widgets_ = {
		{&showObjectWindow, [&](){WidgetObjectWindow();}},
		{&showEngineSettingsWindow, [&](){WidgetEngineSettingsWindow();}},
		{&showTerrainWindow, [&](){WidgetTerrainWindow();}},
		{&showLightWindow, [&](){WidgetLightWindow();}},
		{&showLogWindow, [&](){WidgetLogWindow();}},
		{&showOldSceneWindow, [&](){WidgetRenderWindow(ImVec2(800, 600));}},
		{&showStatsWindow, [&](){WidgetRenderStats();}},
		{&show_inspector_window_, [&](){WidgetInspectorWindow();}}
	};
}

imguiManager::~imguiManager()
{
}

bool imguiManager::Initialize(HWND hwnd, ID3D11Device* device, ID3D11DeviceContext* deviceContext)
{
    Logger::Get().Log("Initializing imgui", __FILE__, __LINE__, Logger::LogLevel::Initialize);

    m_device = device;
    m_deviceContext = deviceContext;

    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    io = &ImGui::GetIO();
    io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
    io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
	io->FontGlobalScale = 1.0f;

    ImGui_ImplWin32_Init(hwnd);
    ImGui_ImplDX11_Init(m_device, m_deviceContext);

    // Appliquer un th�me sombre de base
    ImGui::StyleColorsDark();
    
    // D�finir les couleurs pour une interface de type �diteur sobre
    ImGuiStyle& style = ImGui::GetStyle();
    
    // Palette de couleurs sobres inspir�e des �diteurs modernes
    ImVec4 background_dark = ImVec4(0.10f, 0.10f, 0.10f, 1.00f);    // Fond fonc�
    ImVec4 background = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);         // Fond principal
    ImVec4 background_light = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);   // Fond clair
    ImVec4 accent = ImVec4(0.14f, 0.44f, 0.80f, 0.50f);             // Accent bleu
    ImVec4 accent_light = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);       // Accent bleu vif
	ImVec4 text = ImVec4(1.0f, 1.0f, 1.0f, 1.00f);                // Texte plus blanc
	ImVec4 text_dim = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
    
    // Ajustements de style g�n�raux
	style.WindowPadding = ImVec2(4.0f, 4.0f);       // Moins de padding dans les fen�tres
	style.FramePadding = ImVec2(4.0f, 3.0f);        // Moins de padding dans les cadres
	style.ItemSpacing = ImVec2(4.0f, 3.0f);         // Moins d'espace entre les widgets
	style.ItemInnerSpacing = ImVec2(3.0f, 3.0f);    // Moins d'espace interne
	style.DisplayWindowPadding = ImVec2(0.0f, 0.0f); // Pas de padding pour l'affichage
	style.DisplaySafeAreaPadding = ImVec2(0.0f, 0.0f);
    style.TouchExtraPadding = ImVec2(0.0f, 0.0f);
    style.IndentSpacing = 20.0f;
    style.ScrollbarSize = 14.0f;
    style.GrabMinSize = 10.0f;
    
    // Arrondis
    style.WindowRounding = 4.0f;
    style.ChildRounding = 4.0f;
    style.FrameRounding = 3.0f;
    style.PopupRounding = 4.0f;
    style.ScrollbarRounding = 9.0f;
    style.GrabRounding = 3.0f;
    style.TabRounding = 4.0f;
    
    // Couleurs principales
    style.Colors[ImGuiCol_Text] = text;
    style.Colors[ImGuiCol_TextDisabled] = text_dim;
    style.Colors[ImGuiCol_WindowBg] = background;
    style.Colors[ImGuiCol_ChildBg] = background_dark;
    style.Colors[ImGuiCol_PopupBg] = background_dark;
    style.Colors[ImGuiCol_Border] = ImVec4(0.25f, 0.25f, 0.27f, 1.00f);
    style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    
    // Encadrements
    style.Colors[ImGuiCol_FrameBg] = background_light;
    style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
    style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
    
    // Titres
    style.Colors[ImGuiCol_TitleBg] = background_dark;
    style.Colors[ImGuiCol_TitleBgActive] = accent;
    style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.12f, 0.12f, 0.12f, 0.90f);
    
    // �l�ments de menu
    style.Colors[ImGuiCol_MenuBarBg] = background_dark;
    style.Colors[ImGuiCol_ScrollbarBg] = background_dark;
    style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
    style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
    style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
    
    // Boutons et interactions
    style.Colors[ImGuiCol_CheckMark] = accent_light;
    style.Colors[ImGuiCol_SliderGrab] = accent;
    style.Colors[ImGuiCol_SliderGrabActive] = accent_light;
    style.Colors[ImGuiCol_Button] = background_light;
    style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
    style.Colors[ImGuiCol_ButtonActive] = accent;
    
    // En-t�tes et onglets
    style.Colors[ImGuiCol_Header] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
    style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
    style.Colors[ImGuiCol_HeaderActive] = accent;
    
    style.Colors[ImGuiCol_Separator] = ImVec4(0.28f, 0.28f, 0.28f, 1.00f);
    style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f);
    style.Colors[ImGuiCol_SeparatorActive] = accent;
    
    style.Colors[ImGuiCol_Tab] = background_dark;
    style.Colors[ImGuiCol_TabHovered] = accent;
    style.Colors[ImGuiCol_TabActive] = accent;
    style.Colors[ImGuiCol_TabUnfocused] = background_dark;
    style.Colors[ImGuiCol_TabUnfocusedActive] = background;
    
    // Autres �l�ments 
    style.Colors[ImGuiCol_DockingPreview] = accent;
    style.Colors[ImGuiCol_DockingEmptyBg] = background_light;

	// Charger une police avec une meilleure nettet�
	ImFontConfig fontConfig;
	fontConfig.OversampleH = 2; // Sur�chantillonnage horizontal
	fontConfig.OversampleV = 2; // Sur�chantillonnage vertical
	fontConfig.PixelSnapH = true; // Alignement sur la grille de pixels
	fontConfig.RasterizerMultiply = 1.2f; // L�g�re augmentation de l'�paisseur
	io->Fonts->AddFontDefault(&fontConfig);

	io->Fonts->Build();

	// OU charger une police personnalis�e (d�commenter si vous avez la police)
	// io->Fonts->AddFontFromFileTTF("assets/fonts/roboto.ttf", 16.0f, &fontConfig);
    

	unsigned char* pixels;
	int width, height;
	io->Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

	// initialize the scene manager
	scene_manager_ = new scene_manager;
	if (!scene_manager_->initialize(app_.get())) {
		Logger::Get().Log("Failed to initialize scene manager", __FILE__, __LINE__, Logger::LogLevel::Error);
		return false;
	}

	stats_ = app_->get_stats();

	total_triangle_count_ = stats_->get_triangle_count_ptr();
	total_vertex_count_ = stats_->get_vertex_count_ptr();

	entity_manager_ = app_->get_entity_manager();
    
    Logger::Get().Log("imgui initialized", __FILE__, __LINE__, Logger::LogLevel::Initialize);
    
    return true;
}

void imguiManager::Shutdown()
{
	Logger::Get().Log("Shutting down imgui", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
	ImGui_ImplDX11_Shutdown();
	ImGui_ImplWin32_Shutdown();
	ImGui::DestroyContext();
	Logger::Get().Log("imgui shutdown", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
}

void imguiManager::Render()
{
	ImGui::Render();

	//app->get_direct_3d()->turn_z_buffer_off();
	//app->get_direct_3d()->enable_alpha_blending();
	
	ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

	//app->get_direct_3d()->disable_alpha_blending();
	//app->get_direct_3d()->turn_z_buffer_on();
}

void imguiManager::NewFrame()
{
	ImGui_ImplDX11_NewFrame();
	ImGui_ImplWin32_NewFrame();
	ImGui::NewFrame();
}

void imguiManager::SetupDockspace() {
    // Configuration du style pour supprimer l'espace autour des fen�tres dock�es
    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
    ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
    ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
    
    // Configuration du style pour les n�uds de dock
    ImGui::PushStyleVar(ImGuiStyleVar_DockingSeparatorSize, 1.0f); // R�duit l'�paisseur des s�parateurs
    
    // Configuration de la fen�tre principale
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
    ImGuiViewport* viewport = ImGui::GetMainViewport();
    ImGui::SetNextWindowPos(viewport->Pos);
    ImGui::SetNextWindowSize(viewport->Size);
    ImGui::SetNextWindowViewport(viewport->ID);
    window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
    window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;

    ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
    
    ImGui::Begin("DockSpace", nullptr, window_flags);
    
    // Pop des styles apr�s avoir cr�� la fen�tre principale
    ImGui::PopStyleVar(4); // 4 car nous avons pouss� 4 variables de style
    ImGui::PopStyleColor();

    // Configuration du DockSpace
    ImGuiID dockspace_id = ImGui::GetID("MainDockSpace");
    ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
    ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);

    if (ImGui::BeginMenuBar()) {
        if (ImGui::BeginMenu("Windows")) {
            ImGui::MenuItem("Object Window", NULL, &showObjectWindow);
            ImGui::MenuItem("Terrain Window", NULL, &showTerrainWindow);
            ImGui::MenuItem("Light Window", NULL, &showLightWindow);
            ImGui::MenuItem("Engine Settings Window", NULL, &showEngineSettingsWindow);
            ImGui::MenuItem("Log Window", NULL, &showLogWindow);
            ImGui::MenuItem("render Stats", NULL, &showStatsWindow);
            ImGui::EndMenu();
        }

    	if (ImGui::BeginMenu("Scene")) {
    		if (ImGui::MenuItem("Save Scene")) {
    			scene_manager_->save_scene();
    		}
    		if (ImGui::MenuItem("Save Scene As...")) {
    			scene_manager_->save_scene_as();
    		}
    		if (ImGui::MenuItem("Load Scene")) {
    			scene_manager_->load_scene();
    		}
    		ImGui::EndMenu();
    	}

        ImGui::EndMenuBar();
    }

    ImGui::End();
}

void imguiManager::WidgetSpeedSlider(float* speed)
{
	ImGui::SliderFloat("Speed", speed, 0.0f, 100.0f);
}

void imguiManager::WidgetButton()
{
	static int counter = 0;

	if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
		counter++;
	ImGui::SameLine();
	ImGui::Text("counter = %d", counter);
}

void imguiManager::WidgetAddObject()
{
	if (ImGui::CollapsingHeader("Objects"))
	{
		if (ImGui::Button("Add Cube"))
		{
			app_->add_cube();
		}
		ImGui::SameLine();
		if (ImGui::Button("Import Object"))
		{
			// Open file dialog
			OPENFILENAME ofn;
			WCHAR szFile[260];
			ZeroMemory(&ofn, sizeof(ofn));
			ofn.lStructSize = sizeof(ofn);
			ofn.hwndOwner = NULL;
			ofn.lpstrFile = szFile;
			ofn.lpstrFile[0] = '\0';
			ofn.nMaxFile = sizeof(szFile);
			ofn.lpstrFilter = L"OBJ\0*.obj\0KOBJ\0*.kobj\0TXT\0*.txt";
			ofn.nFilterIndex = 1;
			ofn.lpstrFileTitle = NULL;
			ofn.nMaxFileTitle = 0;
			ofn.lpstrInitialDir = NULL;
			ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

			if (GetOpenFileName(&ofn))
			{
				std::wstring filepath = ofn.lpstrFile;

				WCHAR exePath[MAX_PATH];
				GetModuleFileName(NULL,exePath,MAX_PATH);
				std::wstring exeDir = exePath;
				size_t pos = exeDir.find_last_of(L"\\/");
				if(pos != std::wstring::npos)
				{
					exeDir = exeDir.substr(0, pos);
				}

				std::wstring targetDir = exeDir + L"\\Content\\Assets\\Kobject";


				DWORD ftyp = GetFileAttributesW(targetDir.c_str());
				if( ftyp == INVALID_FILE_ATTRIBUTES)
				{
					std::wstring contentDir = exeDir + L"\\Content";
					if (GetFileAttributes(contentDir.c_str()) == INVALID_FILE_ATTRIBUTES)
					{
						CreateDirectory(contentDir.c_str(), NULL);
					}
					std::wstring assetsDir = contentDir + L"\\Assets";
					if (GetFileAttributes(assetsDir.c_str()) == INVALID_FILE_ATTRIBUTES)
					{
						CreateDirectory(assetsDir.c_str(), NULL);
					}
					std::wstring kobjectDir = assetsDir + L"\\Kobject";
					if (GetFileAttributes(kobjectDir.c_str()) == INVALID_FILE_ATTRIBUTES)
					{
						CreateDirectory(kobjectDir.c_str(), NULL);
					}
				}

				size_t posFile = filepath.find_last_of(L"\\/");
				std::wstring filename = (posFile != std::wstring::npos) ? filepath.substr(posFile + 1) : filepath;

				std::wstring targetPath = targetDir + L"\\" + filename;

				if (!CopyFile(filepath.c_str(), targetPath.c_str(), FALSE))
				{
					// En cas d'erreur, vous pouvez g�rer ici l'erreur (par exemple afficher un message)
					MessageBox(NULL, L"Erreur lors de la copie du fichier.", L"Erreur", MB_OK);
				}
				else
				{
					// On r�cup�re le chemin relatif par rapport � exeDir
					std::wstring relativePath = targetPath.substr(exeDir.size());
        
					// Suppression du premier caract�re s'il s'agit d'un antislash
					if (!relativePath.empty() && (relativePath[0] == L'\\' || relativePath[0] == L'/'))
					{
						relativePath.erase(0, 1);
					}
        
					// Remplacer les antislashs par des slashs
					std::replace(relativePath.begin(), relativePath.end(), L'\\', L'/');
					app_->add_kobject(relativePath);
				}
				
			}

		}
		ImGui::SameLine();
		ImGui::Text("Number of cubes: %d", entity_manager_->GetEntityCount());
	}
}

void imguiManager::WidgetObjectWindow()
{
	ImGui::Begin("Objects", &showObjectWindow);

	if (ImGui::Button("Add Cube")) { app_->add_cube(); }
	ImGui::SameLine();
	if (ImGui::Button("Import Object"))
	{
		// Open file dialog
		OPENFILENAME ofn;
		WCHAR szFile[260];
		ZeroMemory(&ofn, sizeof(ofn));
		ofn.lStructSize = sizeof(ofn);
		ofn.hwndOwner = NULL;
		ofn.lpstrFile = szFile;
		ofn.lpstrFile[0] = '\0';
		ofn.nMaxFile = sizeof(szFile);
		ofn.lpstrFilter = L"OBJ\0*.obj\0KOBJ\0*.kobj\0TXT\0*.txt";
		ofn.nFilterIndex = 1;
		ofn.lpstrFileTitle = NULL;
		ofn.nMaxFileTitle = 0;
		ofn.lpstrInitialDir = NULL;
		ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

		if (GetOpenFileName(&ofn))
		{
			std::wstring filepath = ofn.lpstrFile;

			WCHAR exePath[MAX_PATH];
			GetModuleFileName(NULL,exePath,MAX_PATH);
			std::wstring exeDir = exePath;
			size_t pos = exeDir.find_last_of(L"\\/");
			if(pos != std::wstring::npos)
			{
				exeDir = exeDir.substr(0, pos);
			}

			std::wstring targetDir = exeDir + L"\\Content\\Assets\\Kobject";


			DWORD ftyp = GetFileAttributesW(targetDir.c_str());
			if( ftyp == INVALID_FILE_ATTRIBUTES)
			{
				std::wstring contentDir = exeDir + L"\\Content";
				if (GetFileAttributes(contentDir.c_str()) == INVALID_FILE_ATTRIBUTES)
				{
					CreateDirectory(contentDir.c_str(), NULL);
				}
				std::wstring assetsDir = contentDir + L"\\Assets";
				if (GetFileAttributes(assetsDir.c_str()) == INVALID_FILE_ATTRIBUTES)
				{
					CreateDirectory(assetsDir.c_str(), NULL);
				}
				std::wstring kobjectDir = assetsDir + L"\\Kobject";
				if (GetFileAttributes(kobjectDir.c_str()) == INVALID_FILE_ATTRIBUTES)
				{
					CreateDirectory(kobjectDir.c_str(), NULL);
				}
			}

			size_t posFile = filepath.find_last_of(L"\\/");
			std::wstring filename = (posFile != std::wstring::npos) ? filepath.substr(posFile + 1) : filepath;

			std::wstring targetPath = targetDir + L"\\" + filename;

			if (!CopyFile(filepath.c_str(), targetPath.c_str(), FALSE))
			{
				// En cas d'erreur, vous pouvez g�rer ici l'erreur (par exemple afficher un message)
				MessageBox(NULL, L"Erreur lors de la copie du fichier.", L"Erreur", MB_OK);
			}
			else
			{
				// On r�cup�re le chemin relatif par rapport � exeDir
				std::wstring relativePath = targetPath.substr(exeDir.size());
    
				// Suppression du premier caract�re s'il s'agit d'un antislash
				if (!relativePath.empty() && (relativePath[0] == L'\\' || relativePath[0] == L'/'))
				{
					relativePath.erase(0, 1);
				}
    
				// Remplacer les antislashs par des slashs
				std::replace(relativePath.begin(), relativePath.end(), L'\\', L'/');
				app_->add_kobject(relativePath);
			}
			
		}

	}
	ImGui::SameLine();
	ImGui::Text("Number of objects: %d", entity_manager_->GetEntityCount());

	ImGui::Separator();

	auto entities = entity_manager_->GetAllEntities();

	ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(4,2));

	for (auto& entity : entities)
	{
		auto identity = entity->GetComponent<ecs::IdentityComponent>();
		if (identity)
		{
			std::string name = identity->GetName();
			if (name.empty()) name = "Entity #" + std::to_string(identity->GetId());

			bool isSelected = (entity->GetID() == m_selected_entity_id);
			if (ImGui::Selectable(name.c_str(), isSelected))
			{
				m_selected_entity_id = entity->GetID();
				show_inspector_window_ = true;
			}
		}
	}

	ImGui::PopStyleVar();
	ImGui::End();
}

void imguiManager::WidgetInspectorWindow()
{
	ImGui::Begin("Inspector", &show_inspector_window_);

	auto entity = entity_manager_->GetEntityByID(m_selected_entity_id);
	if (entity)
	{
		auto identity = entity->GetComponent<ecs::IdentityComponent>();
		if (identity)
		{
			char name[256];
			strcpy_s(name, identity->GetName().c_str());
			if (ImGui::InputText("Name", name, sizeof(name)))
			{
				identity->SetName(std::string(name));
			}
			ImGui::Text("ID: %d", identity->GetId());
		}

		ImGui::Separator();

		// Lister et afficher les composants
		auto components = entity->GetAllComponents();
		for (auto& pair : components)
		{
			auto& comp = pair.second;
			// Utiliser le nom du type comme en-tete
			std::string compName = typeid(*comp).name();
			if (ImGui::CollapsingHeader(compName.c_str()))
			{
				comp->OnImGuiRender();
			}
		}

		if (ImGui::Button("Delete Entity"))
		{
			entity_manager_->DestroyEntity(m_selected_entity_id);
			m_selected_entity_id = -1;
			show_inspector_window_ = false;
		}
		ImGui::SameLine();

		if (ImGui::Button("Add Component"))
		{
			ImGui::OpenPopup("AddComponentPopup");
		}

		if (ImGui::BeginPopup("AddComponentPopup"))
		{
			ImGui::Text("Select Component to Add:");
			ImGui::Separator();

			if (ImGui::MenuItem("Transform Component"))
			{
				if (!entity->HasComponent<ecs::TransformComponent>())
				{
					entity->AddComponent<ecs::TransformComponent>();
				}
				ImGui::CloseCurrentPopup();
			}
			if (ImGui::MenuItem("Model Path Component"))
			{
				if (!entity->HasComponent<ecs::ModelPathComponent>())
				{
					entity->AddComponent<ecs::ModelPathComponent>();
				}
				ImGui::CloseCurrentPopup();
			}
			if (ImGui::MenuItem("Audio Component"))
			{
				if (!entity->HasComponent<ecs::AudioComponent>())
				{
					entity->AddComponent<ecs::AudioComponent>();
				}
				ImGui::CloseCurrentPopup();
			}
			if (ImGui::MenuItem("Physics Component"))
			{
				if (!entity->HasComponent<ecs::PhysicsComponent>())
				{
					entity->AddComponent<ecs::PhysicsComponent>();
				}
				ImGui::CloseCurrentPopup();
			}
			if (ImGui::MenuItem("Render Component"))
			{
				if (!entity->HasComponent<ecs::RenderComponent>())
				{
					entity->AddComponent<ecs::RenderComponent>();
				}
				ImGui::CloseCurrentPopup();
			}
			if (ImGui::MenuItem("Shader Component"))
			{
				if (!entity->HasComponent<ecs::ShaderComponent>())
				{
					entity->AddComponent<ecs::ShaderComponent>();
				}
				ImGui::CloseCurrentPopup();
			}
			ImGui::EndPopup();
			
		}
	}
	else
	{
		ImGui::Text("No entity selected.");
	}

	ImGui::End();
}

void imguiManager::WidgetTerrainWindow()
{
	ImGui::Begin("Terrain", &showTerrainWindow);

	ImGui::Text("Number of terrain cubes: %d", app_->get_terrain_entity_count());

	ImGui::Separator();

	if (ImGui::Button("Generate Flat Terrain"))
	{
		app_->generate_terrain();
	}
	
	ImGui::Separator();

	// Input for the number of cubes on each side
	ImGui::Text("Number of cubes on each side: ");
	ImGui::SameLine();
	ImGui::InputInt("##SideCount", &m_SideCount);
	if (m_SideCount < 1)
	{
		m_SideCount = 1;
	}
	
	ImGui::Separator();

	if (ImGui::Button("Generate BigCube Terrain"))
	{
		app_->create_big_cube(m_SideCount);
	}

	ImGui::Separator();

	if (ImGui::Button("Delete All Terrain Cubes"))
	{
		app_->delete_terrain();
	}


	
	ImGui::End();
}

bool imguiManager::ImGuiWidgetRenderer()
{
	// Start the Dear ImGui frame
	NewFrame();

	// Setup the dockspace
	SetupDockspace();

	//ImGui Widget
	ImGui::Begin("Khaotic Engine", NULL);

	float speed = app_->get_speed();
	
	WidgetSpeedSlider(&speed);
	app_->set_speed(speed);
	WidgetButton();
	WidgetAddObject();

	ImGui::End();

	// Read the widget list and call the function if the show variable is true
	for (const auto& entry : widgets_)
	{
		if (*entry.show == true) {entry.func();}
	}
	
	//render imgui
	Render();

	return true;
}

void imguiManager::WidgetLightWindow()
{
	ImGui::Begin("Light", &showLightWindow);
	

	// Sun light settings
	light_class* sunLight = app_->get_sun_light();
	// Direction input
	XMFLOAT3 direction = sunLight->GetDirection();
	float dir[3] = { direction.x, direction.y, direction.z };
	if (ImGui::DragFloat3("Sun Direction", dir))
	{
		sunLight->SetDirection(dir[0], dir[1], dir[2]);
	}
	// Color input
	XMFLOAT4 color = sunLight->GetDiffuseColor();
	float col[3] = { color.x, color.y, color.z };
	if (ImGui::ColorEdit3("Sun Color", col))
	{
		sunLight->SetDiffuseColor(col[0], col[1], col[2], 1.0f);
	}
	// Intensity input
	float intensity = sunLight->GetIntensity();
	if (ImGui::DragFloat("Sun Intensity", &intensity, 0.1f, 0.0f, 100.0f))
	{
		sunLight->SetIntensity(intensity);
	}


	ImGui::Separator();

	int index = 0;

	// Area light settings

	for(auto& light : app_->get_lights())
	{
		std::string headerName = "Light " + std::to_string(index);
		if (ImGui::CollapsingHeader(headerName.c_str()))
		{
			XMVECTOR position = app_->get_light_position(index);
			XMVECTOR color = app_->get_light_color(index);
			float pos[3] = { XMVectorGetX(position), XMVectorGetY(position), XMVectorGetZ(position) };
			float col[3] = { XMVectorGetX(color), XMVectorGetY(color), XMVectorGetZ(color) };

			std::string posLabel = "Position##" + std::to_string(index);
			std::string colLabel = "Color##" + std::to_string(index);

			if (ImGui::DragFloat3(posLabel.c_str(), pos))
			{
				app_->set_light_position(index, XMVectorSet(pos[0], pos[1], pos[2], 0.0f));
			}

			if (ImGui::ColorEdit3(colLabel.c_str(), col))
			{
				app_->set_light_color(index, XMVectorSet(col[0], col[1], col[2], 0.0f));
			}

		}
		index++;
	};

	ImGui::End();
}

void imguiManager::WidgetEngineSettingsWindow()
{
	ImGui::Begin("Engine Settings", &showEngineSettingsWindow);

	// Begining Of General Setting
	ImGui::Text("General");

	// Checkbox for toggling vsync globally in the application class by calling the set_vsync function in the application class when the checkbox state changes
	bool vsync = app_->get_vsync();
	if (ImGui::Checkbox("Vsync", &vsync))
	{
		app_->set_vsync(vsync);
	}

	// End Of General Setting
	ImGui::Separator();
	// culling section
	ImGui::Text("Culling");

	// float input for frustum tolerance
	float frustumTolerance = app_->get_frustum_tolerance();
	if (ImGui::DragFloat("Frustum Tolerance", &frustumTolerance, 0.1f, 0.0f, 100.0f))
	{
		app_->set_frustum_tolerance(frustumTolerance);
	}

	// End Of Culling Setting
	ImGui::Separator();

	// physics section
	ImGui::Text("physics");

	// Input To set the Fixed Update Interval
	int physicsInterval = app_->get_physics_tick_rate();
	if (ImGui::InputInt("physics Tick Rate", &physicsInterval))
	{
		app_->set_physics_tick_rate(physicsInterval);
	}

	// Input to change the gravity on same line
	XMVECTOR gravity = app_->get_physics()->GetGravity();
	float gravityValues[3] = { XMVectorGetX(gravity), XMVectorGetY(gravity), XMVectorGetZ(gravity) };
	if (ImGui::DragFloat3("Gravity", gravityValues))
	{
		app_->get_physics()->SetGravity(XMVectorSet(gravityValues[0], gravityValues[1], gravityValues[2], 0.0f));
	}

	ImGui::End();
}

void imguiManager::WidgetLogWindow()
{
    ImGui::Begin("Log Window" , &showLogWindow);

    // Filtre de recherche
    static ImGuiTextFilter filter;
    filter.Draw("Filter ", 180);

	ImGui::SameLine();

	// Bouton pour ouvrir le fichier de log
	if (ImGui::Button("Open Log File"))
	{
		ShellExecuteA(NULL, "open", Logger::Get().m_logFilePath.c_str(), NULL, NULL, SW_SHOWNORMAL);
	}

    // Place the menu on the same line as the filter
    ImGui::SameLine();

    // Menu d�roulant pour les niveaux de log
    if (ImGui::BeginMenu("Log Levels"))
    {
        for (size_t i = 0; i < Logger::LogLevelCount; ++i)
        {
            bool isVisible = !Logger::Get().m_disabledLogLevels[i];
            if (ImGui::Checkbox(Logger::Get().GetLogLevelInfo(static_cast<Logger::LogLevel>(i)).name, &isVisible))
            {
                Logger::Get().m_disabledLogLevels[i] = !isVisible;
            }
        }
        ImGui::EndMenu();
    }

	const auto& logBuffer = Logger::Get().GetLogBuffer();
	std::vector<Logger::LogEntry> logfiltered;
	int logCount = logBuffer.size();

    // Affichage des logs filtr�s
    ImGui::BeginChild("Log");

	for (const auto& log : logBuffer)
	{
		if (filter.PassFilter(log.message.c_str()) && !Logger::Get().m_disabledLogLevels[static_cast<size_t>(log.level)])
		{
			logfiltered.push_back(log);
		}
	}

	if (logfiltered.size() == 0)
	{
		ImGui::Text("No logs to display.");
	}
	else
	{
		ImGuiListClipper clipper;
		clipper.Begin(logCount);
		while (clipper.Step())
		{
			for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
			{
				if (i < logfiltered.size()) {
					const auto& log = logfiltered[i];
					ImGui::TextColored(Logger::Get().GetLogLevelInfo(log.level).color, log.message.c_str());
				}
				
			}
		}
		clipper.End();
	}

	// Scroll to the bottom
	if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
	{
		ImGui::SetScrollHereY(1.0f);
	}

    ImGui::EndChild();

    ImGui::End();
}

void imguiManager::WidgetRenderWindow(ImVec2 availableSize)
{
	ImGui::Begin("render Window");

	ImVec2 oldWindowSize = windowSize;
	windowSize = ImGui::GetContentRegionAvail();
	
	// Si la taille de la fen�tre a chang�, ajustez la taille de la fen�tre de l'application
	if (oldWindowSize.x != windowSize.x || oldWindowSize.y != windowSize.y)
	{
		app_->set_window_size(windowSize);
	}
	

	// Get the aspect ratio of the scene in app
	float aspectRatio = app_->get_aspect_ratio();
	// calculate the size of the window
	if (windowSize.x / windowSize.y > aspectRatio)
	{
		windowSize.x = windowSize.y * aspectRatio;
	}
	else
	{
		windowSize.y = windowSize.x / aspectRatio;
	}
	
	ID3D11ShaderResourceView* texture = app_->get_scene_texture()->GetShaderResourceView();
	if (texture)
	{
		
		// Affichez la scenne projet� sur texture dans une fen�tre ImGui
		// alpha blend is not enable to render the texture

		app_->get_direct_3d()->turn_z_buffer_off();
		app_->get_direct_3d()->enable_alpha_blending();
		
		ImGui::Image((ImTextureID)texture, windowSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(1, 1, 1, 1));
	}
	else
	{
		ImGui::Text("render texture is not available.");
	}

	ImGui::End();
}

void imguiManager::WidgetRenderStats()
{
    ImGui::Begin("render Stats");

	current_fps_ = stats_->get_current_fps();
	min_fps_ = stats_->get_min_fps();
	max_fps_ = stats_->get_max_fps();
	draw_calls_ = stats_->get_draw_calls();

	
	// total_vertex_count_ = stats_->get_total_vertex_count();
	// total_triangle_count_ = stats_->get_total_triangle_count();
	
	visible_triangle_count_ = stats_->get_visible_triangle_count();
	current_frame_time_ = stats_->get_frame_time();
	
    m_frameTimeHistory[m_frameTimeHistoryIndex] = current_frame_time_;
    m_frameTimeHistoryIndex = (m_frameTimeHistoryIndex + 1) % FRAME_HISTORY_COUNT;

    ImGui::Text("FPS: %d", current_fps_);
    ImGui::SameLine();
    ImGui::Text("Min Fps: %d", min_fps_);
    ImGui::SameLine();
    ImGui::Text("Max Fps: %d", max_fps_);

    ImGui::Separator();

    // Trouver les valeurs min/max pour l'�chelle du graphique
    float frameTimeMin = FLT_MAX;
    float frameTimeMax = 0.0f;
    for (int i = 0; i < FRAME_HISTORY_COUNT; i++) {
        if (m_frameTimeHistory[i] > 0.0f) {
            frameTimeMin = min(frameTimeMin, m_frameTimeHistory[i]);
            frameTimeMax = max(frameTimeMax, m_frameTimeHistory[i]);
        }
    }
    // S'assurer d'avoir au moins une petite plage
    if (frameTimeMax == 0.0f) frameTimeMax = 0.033f; // ~30 FPS
    if (frameTimeMin == FLT_MAX) frameTimeMin = 0.0f;
    
    // Ajouter 10% de marge pour la lisibilit�
    float margin = (frameTimeMax - frameTimeMin) * 0.1f;
    frameTimeMin = max(0.0f, frameTimeMin - margin);
    frameTimeMax += margin;

    // Afficher le graphique
    ImGui::Text("Frame Time: %.3f ms", current_frame_time_ * 1000.0f);
	ImGui::PlotLines("FrameTimeGraph", // Au lieu de cha�ne vide ""
				 m_frameTimeHistory, 
				 FRAME_HISTORY_COUNT, 
				 m_frameTimeHistoryIndex, 
				 "", 
				 frameTimeMin, 
				 frameTimeMax, 
				 ImVec2(0, 80));

    ImGui::Text("Draw Calls: %d", draw_calls_);

    ImGui::Separator();

    ImGui::Text("Statistiques de rendu:");
    ImGui::Text("Vertices total: %d", *total_vertex_count_);

    ImGui::Text("Triangles total: %d", *total_triangle_count_);
    ImGui::SameLine();
    ImGui::Text("Triangles visibles: %d", visible_triangle_count_);

	app_->get_direct_3d()->get_video_card_info(card_name_, video_memory_);
	cpu_name_ = stats_->get_cpu_name();
	version_driver_ = stats_->get_gpu_driver_version(app_->get_direct_3d()->get_device());
	
	ImGui::Columns(3, "GPUCPURAMColumns", false);
	ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.33f);
	ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.33f);

	// Premier collapsing header pour les informations GPU
	if (ImGui::CollapsingHeader("Informations GPU"))
	{
		ImGui::Text("Carte graphique: %s", card_name_);
		ImGui::Text("Memoire video: %d Mo", video_memory_);
		ImGui::Text("Pilote: %s", version_driver_.c_str());
	}

	ImGui::NextColumn();

	// Second collapsing header pour les informations CPU
	if (ImGui::CollapsingHeader("Informations CPU"))
	{
		SYSTEM_INFO sysInfo;
		GetSystemInfo(&sysInfo);
		ImGui::Text("Processeur: %s", cpu_name_.c_str());
		ImGui::Text("Nombre de coeurs: %u", sysInfo.dwNumberOfProcessors);
		ImGui::Text("Architecture: %s", (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ? "x64" : "x86");
		ImGui::Text("Taille de la page: %u octets", sysInfo.dwPageSize);
		ImGui::Text("Taille du cache: %u octets", sysInfo.dwAllocationGranularity);
		ImGui::Text("Type de processeur: %u", sysInfo.wProcessorLevel);
		ImGui::Text("Version du processeur: %u", sysInfo.wProcessorRevision);
	}

	ImGui::NextColumn();

	if (ImGui::CollapsingHeader("Informations RAM"))
	{
		MEMORYSTATUSEX mem_info;
		mem_info.dwLength = sizeof(MEMORYSTATUSEX);
		GlobalMemoryStatusEx(&mem_info);
		ImGui::Text("Memoire totale: %llu Mo", mem_info.ullTotalPhys / (1024 * 1024));
		ImGui::Text("Memoire disponible: %llu Mo", mem_info.ullAvailPhys / (1024 * 1024));
		ImGui::Text("Memoire utilisee: %llu Mo", (mem_info.ullTotalPhys - mem_info.ullAvailPhys) / (1024 * 1024));
	}

	ImGui::Columns(1);

    ImGui::End();
}

