#include "StaticGeometryMemberEditor.hpp"
#include "../components/StaticGeometry.hpp"
#include "../components/LodSettings.hpp"
#include <imgui.h>
#include <OgreResourceGroupManager.h>
#include <algorithm>
#include <cstring>

StaticGeometryMemberEditor::StaticGeometryMemberEditor(Ogre::SceneManager *sceneMgr)
	: m_sceneMgr(sceneMgr)
{
}

void StaticGeometryMemberEditor::scanMeshFiles()
{
	if (m_meshesScanned)
		return;

	m_meshFiles.clear();

	// Get all resource groups
	Ogre::ResourceGroupManager &rgm = Ogre::ResourceGroupManager::getSingleton();
	Ogre::StringVector groups = rgm.getResourceGroups();

	for (const auto &group : groups) {
		// Get file info for this group
		Ogre::FileInfoListPtr fileList = rgm.findResourceFileInfo(group, "*");

		if (fileList) {
			for (const auto &fileInfo : *fileList) {
				const std::string &filename = fileInfo.filename;
				// Check for supported extensions
				if (filename.size() > 5) {
					std::string ext = filename.substr(filename.find_last_of('.') + 1);
					// Convert to lowercase
					std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
					
					if (ext == "mesh" || ext == "gltf" || ext == "glb") {
						m_meshFiles.push_back(filename);
					}
				}
			}
		}
	}

	// Sort and remove duplicates
	std::sort(m_meshFiles.begin(), m_meshFiles.end());
	m_meshFiles.erase(std::unique(m_meshFiles.begin(), m_meshFiles.end()),
			  m_meshFiles.end());

	m_meshesScanned = true;
}

bool StaticGeometryMemberEditor::matchesSearch(const std::string &meshName,
					      const std::string &search)
{
	if (search.empty())
		return true;

	std::string lowerMesh = meshName;
	std::string lowerSearch = search;
	std::transform(lowerMesh.begin(), lowerMesh.end(), lowerMesh.begin(), ::tolower);
	std::transform(lowerSearch.begin(), lowerSearch.end(), lowerSearch.begin(), ::tolower);

	return lowerMesh.find(lowerSearch) != std::string::npos;
}

void StaticGeometryMemberEditor::renderMeshBrowser(StaticGeometryMemberComponent &member)
{
	if (ImGui::BeginPopupModal("Mesh Browser (StaticGeometry)", &m_showMeshBrowser,
				   ImGuiWindowFlags_AlwaysAutoResize)) {
		ImGui::Text("Search:");
		ImGui::SameLine();
		ImGui::InputText("##search", m_searchBuffer, sizeof(m_searchBuffer));

		ImGui::Separator();

		// Show filtered mesh list
		ImGui::BeginChild("MeshList", ImVec2(400, 300), true);

		std::string searchStr(m_searchBuffer);

		for (const auto &meshName : m_meshFiles) {
			if (!matchesSearch(meshName, searchStr))
				continue;

			// Highlight current selection
			bool isCurrent = (member.meshName == meshName);
			if (isCurrent) {
				ImGui::PushStyleColor(ImGuiCol_Text,
						      ImVec4(0.2f, 0.8f, 0.2f, 1.0f));
			}

			if (ImGui::Selectable(meshName.c_str(), isCurrent)) {
				member.meshName = meshName;
				member.markDirty();
			}

			if (isCurrent) {
				ImGui::PopStyleColor();
			}
		}

		if (m_meshFiles.empty()) {
			ImGui::TextDisabled("No mesh files found");
		}

		ImGui::EndChild();

		ImGui::Separator();

		// Show count
		int visibleCount = 0;
		for (const auto &meshName : m_meshFiles) {
			if (matchesSearch(meshName, searchStr))
				visibleCount++;
		}
		ImGui::Text("Showing %d of %zu meshes", visibleCount, m_meshFiles.size());

		// Buttons
		if (ImGui::Button("Select", ImVec2(120, 0))) {
			m_showMeshBrowser = false;
			ImGui::CloseCurrentPopup();
		}

		ImGui::SameLine();

		if (ImGui::Button("Cancel", ImVec2(120, 0))) {
			m_showMeshBrowser = false;
			ImGui::CloseCurrentPopup();
		}

		ImGui::SameLine();

		if (ImGui::Button("Refresh", ImVec2(120, 0))) {
			m_meshesScanned = false;
			scanMeshFiles();
		}

		ImGui::EndPopup();
	}
}

void StaticGeometryMemberEditor::renderRegionSelector(flecs::entity entity, StaticGeometryMemberComponent& member)
{
	// Get the world from the entity
	flecs::world world = entity.world();
	
	// Collect all region entities
	std::vector<flecs::entity> regionEntities;
	std::vector<std::string> regionIds;
	std::vector<std::string> regionNames;
	
	int currentIndex = -1;
	world.query<StaticGeometryComponent>().each([&](flecs::entity e, StaticGeometryComponent& region) {
		regionEntities.push_back(e);
		regionIds.push_back(region.regionId);
		regionNames.push_back(region.regionName.empty() ? "Region " + std::to_string(e.id()) : region.regionName);
		
		if (member.regionEntity == e || member.regionId == region.regionId) {
			currentIndex = (int)regionEntities.size() - 1;
		}
	});
	
	// Default to first region if none selected
	if (currentIndex == -1 && !regionEntities.empty()) {
		currentIndex = 0;
		member.regionEntity = regionEntities[0];
		member.regionId = regionIds[0];
		member.markDirty();
	}
	
	// Build combo string
	std::string comboItems;
	for (size_t i = 0; i < regionNames.size(); ++i) {
		if (i > 0) comboItems += '\0';
		comboItems += regionNames[i] + " (" + regionIds[i] + ")";
	}
	comboItems += '\0';
	
	int newIndex = currentIndex < 0 ? 0 : currentIndex;
	if (ImGui::Combo("Region", &newIndex, comboItems.c_str())) {
		if (newIndex >= 0 && newIndex < (int)regionEntities.size()) {
			member.regionEntity = regionEntities[newIndex];
			member.regionId = regionIds[newIndex];
			member.markDirty();
		}
	}
	
	if (regionEntities.empty()) {
		ImGui::TextColored(ImVec4(1, 0, 0, 1), "No StaticGeometry regions! Create one first.");
	}
}

void StaticGeometryMemberEditor::renderLodSettingsSelector(flecs::entity entity, StaticGeometryMemberComponent& member)
{
	// Get the world from the entity
	flecs::world world = entity.world();
	
	// Collect all LOD settings entities
	std::vector<flecs::entity> settingsEntities;
	std::vector<std::string> settingsIds;
	std::vector<std::string> displayNames;
	
	int currentIndex = -1;
	int noneIndex = -1;
	
	// Add "None" option
	displayNames.push_back("None (no LOD)");
	settingsEntities.push_back(flecs::entity::null());
	settingsIds.push_back("");
	noneIndex = 0;
	
	world.query<LodSettingsComponent>().each([&](flecs::entity e, LodSettingsComponent& settings) {
		settingsEntities.push_back(e);
		settingsIds.push_back(settings.settingsId);
		
		std::string displayName = settings.settingsId;
		if (displayName.empty()) {
			displayName = "LOD Settings " + std::to_string(e.id());
		}
		displayNames.push_back(displayName);
		
		if (settings.settingsId == member.lodSettingsId) {
			currentIndex = (int)settingsEntities.size() - 1;
			member.lodSettingsEntity = e;
		}
	});
	
	// If no selection but has ID, try to find it
	if (currentIndex == -1 && !member.lodSettingsId.empty()) {
		for (size_t i = 0; i < settingsIds.size(); ++i) {
			if (settingsIds[i] == member.lodSettingsId) {
				currentIndex = (int)i;
				member.lodSettingsEntity = settingsEntities[i];
				break;
			}
		}
	}
	
	// Default to "None" if not found
	if (currentIndex == -1) {
		currentIndex = noneIndex;
	}
	
	// Build combo string
	std::string comboItems;
	for (size_t i = 0; i < displayNames.size(); ++i) {
		if (i > 0) comboItems += '\0';
		comboItems += displayNames[i];
	}
	comboItems += '\0';
	
	int newIndex = currentIndex;
	if (ImGui::Combo("LOD Settings", &newIndex, comboItems.c_str())) {
		if (newIndex >= 0 && newIndex < (int)settingsEntities.size()) {
			if (newIndex == noneIndex) {
				member.lodSettingsId.clear();
				member.lodSettingsEntity = flecs::entity::null();
			} else {
				member.lodSettingsId = settingsIds[newIndex];
				member.lodSettingsEntity = settingsEntities[newIndex];
			}
			member.markDirty();
		}
	}
	
	// Show warning if no LOD settings available
	if (settingsEntities.size() <= 1) {
		ImGui::TextDisabled("Create a LOD Settings entity to enable LOD");
	}
	
	// Show info about selected settings
	if (!member.lodSettingsId.empty() && member.lodSettingsEntity.is_alive()) {
		const auto& settings = member.lodSettingsEntity.get<LodSettingsComponent>();
		ImGui::TextDisabled("Levels: %zu, Strategy: %s", 
			settings.lodLevels.size(),
			settings.strategy == LodSettingsComponent::Strategy::Distance ? "Distance" :
			settings.strategy == LodSettingsComponent::Strategy::PixelCount ? "Pixel Count" : "Edge Pixel");
	}
}

bool StaticGeometryMemberEditor::renderComponent(flecs::entity entity, StaticGeometryMemberComponent &member)
{
	bool changed = false;
	
	// Region selection
	renderRegionSelector(entity, member);
	
	ImGui::Separator();
	
	// LOD Settings selection
	renderLodSettingsSelector(entity, member);
	
	ImGui::Separator();
	
	// Mesh selection with browser
	char meshBuf[256];
	std::strncpy(meshBuf, member.meshName.c_str(), sizeof(meshBuf) - 1);
	meshBuf[sizeof(meshBuf) - 1] = '\0';
	
	if (ImGui::InputText("Mesh Name", meshBuf, sizeof(meshBuf))) {
		member.meshName = meshBuf;
		member.markDirty();
		changed = true;
	}
	
	ImGui::SameLine();
	if (ImGui::Button("Browse...")) {
		scanMeshFiles();
		m_showMeshBrowser = true;
		m_searchBuffer[0] = '\0';
	}
	
	// Mesh Browser Popup
	if (m_showMeshBrowser) {
		ImGui::OpenPopup("Mesh Browser (StaticGeometry)");
	}
	
	renderMeshBrowser(member);
	
	ImGui::Separator();
	
	// Material input (simple text input)
	char matBuf[256];
	std::strncpy(matBuf, member.materialName.c_str(), sizeof(matBuf) - 1);
	matBuf[sizeof(matBuf) - 1] = '\0';
	
	if (ImGui::InputText("Material Override", matBuf, sizeof(matBuf))) {
		member.materialName = matBuf;
		member.markDirty();
		changed = true;
	}
	ImGui::TextDisabled("(Empty = use mesh default material)");
	
	ImGui::Separator();
	
	// Options
	if (ImGui::Checkbox("Cast Shadows", &member.castShadows)) {
		member.markDirty();
		changed = true;
	}
	
	if (ImGui::Checkbox("Visible", &member.visible)) {
		member.markDirty();
		changed = true;
	}
	
	// Info notes
	ImGui::Separator();
	ImGui::TextDisabled("Note: Position/Orientation uses Transform component's SceneNode.");
	ImGui::TextDisabled("LOD: All members in a region must use the same LOD Settings!");
	
	// Status
	ImGui::Separator();
	if (member.dirty) {
		ImGui::TextColored(ImVec4(1, 1, 0, 1), "Status: Modified (needs rebuild)");
	} else {
		ImGui::TextColored(ImVec4(0, 1, 0, 1), "Status: Up to date");
	}
	
	return changed;
}
