#include "TriangleBufferEditor.hpp"
#include "../components/ProceduralTexture.hpp"
#include "../components/ProceduralMaterial.hpp"
#include "../components/StaticGeometry.hpp"
#include "../components/Primitive.hpp"
#include <imgui.h>

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

void TriangleBufferEditor::renderTextureSelector(flecs::entity entity, TriangleBufferComponent &tb)
{
	flecs::world world = entity.world();
	
	std::vector<flecs::entity> textureEntities;
	std::vector<std::string> textureNames;
	
	int currentIndex = -1;
	int noneIndex = 0;
	
	textureEntities.push_back(flecs::entity::null());
	textureNames.push_back("None");
	
	world.query<ProceduralTextureComponent>().each([&](flecs::entity e, ProceduralTextureComponent& tex) {
		textureEntities.push_back(e);
		std::string name = tex.textureName.empty() ? "Texture " + std::to_string(e.id()) : tex.textureName;
		textureNames.push_back(name);
		
		if (tb.textureEntity == e) {
			currentIndex = (int)textureEntities.size() - 1;
		}
	});
	
	if (currentIndex == -1) currentIndex = noneIndex;
	
	std::string comboItems;
	for (size_t i = 0; i < textureNames.size(); ++i) {
		if (i > 0) comboItems += '\0';
		comboItems += textureNames[i];
	}
	comboItems += '\0';
	
	int newIndex = currentIndex;
	if (ImGui::Combo("Texture Source", &newIndex, comboItems.c_str())) {
		if (newIndex == noneIndex) {
			tb.textureEntity = flecs::entity::null();
			tb.textureRectName.clear();
		} else {
			tb.textureEntity = textureEntities[newIndex];
		}
		tb.markDirty();
	}
}

void TriangleBufferEditor::renderRectSelector(flecs::entity entity, TriangleBufferComponent &tb)
{
	if (!tb.textureEntity.is_alive() || !tb.textureEntity.has<ProceduralTextureComponent>()) {
		ImGui::TextDisabled("Select a texture first");
		return;
	}
	
	const auto& texture = tb.textureEntity.get<ProceduralTextureComponent>();
	const auto& namedRects = texture.getAllNamedRects();
	
	if (namedRects.empty()) {
		ImGui::TextColored(ImVec4(1, 0.5f, 0, 1), "No named rectangles in texture!");
		ImGui::TextDisabled("Add named rectangles in the Procedural Texture component");
		return;
	}
	
	std::vector<std::string> rectNames;
	int currentIndex = -1;
	int noneIndex = 0;
	
	rectNames.push_back("None (use full texture)");
	
	for (const auto& pair : namedRects) {
		rectNames.push_back(pair.first);
		if (tb.textureRectName == pair.first) {
			currentIndex = (int)rectNames.size() - 1;
		}
	}
	
	if (currentIndex == -1) currentIndex = noneIndex;
	
	std::string comboItems;
	for (size_t i = 0; i < rectNames.size(); ++i) {
		if (i > 0) comboItems += '\0';
		comboItems += rectNames[i];
	}
	comboItems += '\0';
	
	int newIndex = currentIndex;
	if (ImGui::Combo("Texture Rectangle", &newIndex, comboItems.c_str())) {
		if (newIndex == noneIndex) {
			tb.textureRectName.clear();
		} else {
			tb.textureRectName = rectNames[newIndex];
		}
		tb.markDirty();
	}
}

void TriangleBufferEditor::renderMaterialSelector(flecs::entity entity, TriangleBufferComponent &tb)
{
	flecs::world world = entity.world();
	
	std::vector<flecs::entity> materialEntities;
	std::vector<std::string> materialNames;
	
	int currentIndex = -1;
	int noneIndex = 0;
	
	materialEntities.push_back(flecs::entity::null());
	materialNames.push_back("None");
	
	world.query<ProceduralMaterialComponent>().each([&](flecs::entity e, ProceduralMaterialComponent& mat) {
		materialEntities.push_back(e);
		std::string name = mat.materialName.empty() ? "Material " + std::to_string(e.id()) : mat.materialName;
		if (mat.created) name += " (created)";
		else name += " (pending)";
		materialNames.push_back(name);
		
		if (tb.materialEntity == e) {
			currentIndex = (int)materialEntities.size() - 1;
		}
	});
	
	if (currentIndex == -1) currentIndex = noneIndex;
	
	std::string comboItems;
	for (size_t i = 0; i < materialNames.size(); ++i) {
		if (i > 0) comboItems += '\0';
		comboItems += materialNames[i];
	}
	comboItems += '\0';
	
	int newIndex = currentIndex;
	if (ImGui::Combo("Material", &newIndex, comboItems.c_str())) {
		if (newIndex == noneIndex) {
			tb.materialEntity = flecs::entity::null();
		} else {
			tb.materialEntity = materialEntities[newIndex];
		}
		tb.markDirty();
	}
}

void TriangleBufferEditor::renderStaticGeometrySelector(flecs::entity entity, TriangleBufferComponent &tb)
{
	flecs::world world = entity.world();
	
	if (!tb.useStaticGeometry) {
		return;
	}
	
	std::vector<flecs::entity> regionEntities;
	std::vector<std::string> regionNames;
	
	int currentIndex = -1;
	int noneIndex = 0;
	
	regionEntities.push_back(flecs::entity::null());
	regionNames.push_back("None");
	
	world.query<StaticGeometryComponent>().each([&](flecs::entity e, StaticGeometryComponent& region) {
		regionEntities.push_back(e);
		std::string name = region.regionName.empty() ? "Region " + std::to_string(e.id()) : region.regionName;
		regionNames.push_back(name);
		
		if (tb.staticGeometryEntity == e) {
			currentIndex = (int)regionEntities.size() - 1;
		}
	});
	
	if (currentIndex == -1) currentIndex = noneIndex;
	
	std::string comboItems;
	for (size_t i = 0; i < regionNames.size(); ++i) {
		if (i > 0) comboItems += '\0';
		comboItems += regionNames[i];
	}
	comboItems += '\0';
	
	int newIndex = currentIndex;
	if (ImGui::Combo("StaticGeometry Region", &newIndex, comboItems.c_str())) {
		if (newIndex == noneIndex) {
			tb.staticGeometryEntity = flecs::entity::null();
		} else {
			tb.staticGeometryEntity = regionEntities[newIndex];
		}
		tb.markDirty();
	}
	
	if (regionEntities.size() <= 1) {
		ImGui::TextColored(ImVec4(1, 0.5f, 0, 1), "No StaticGeometry regions! Create one first.");
	}
}

bool TriangleBufferEditor::renderComponent(flecs::entity entity, TriangleBufferComponent &tb)
{
	bool modified = false;
	
	if (ImGui::CollapsingHeader("Triangle Buffer", ImGuiTreeNodeFlags_DefaultOpen)) {
		ImGui::Indent();
		
		// Status
		if (tb.meshCreated) {
			ImGui::TextColored(ImVec4(0, 1, 0, 1), "Status: Mesh Created");
			ImGui::Text("Mesh: %s", tb.meshName.c_str());
		} else if (tb.dirty) {
			ImGui::TextColored(ImVec4(1, 1, 0, 1), "Status: Needs Rebuild");
		} else {
			ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1), "Status: Empty");
		}
		
		ImGui::Separator();
		
		// Mesh name
		char nameBuf[256];
		strncpy(nameBuf, tb.meshName.c_str(), sizeof(nameBuf) - 1);
		nameBuf[sizeof(nameBuf) - 1] = '\0';
		
		if (ImGui::InputText("Mesh Name", nameBuf, sizeof(nameBuf))) {
			tb.meshName = nameBuf;
			tb.markDirty();
			modified = true;
		}
		
		ImGui::Separator();
		
		// Texture and UV mapping
		ImGui::Text("Texture Mapping:");
		renderTextureSelector(entity, tb);
		renderRectSelector(entity, tb);
		ImGui::TextDisabled("UVs will be mapped to rectangle with margin from texture");
		
		ImGui::Separator();
		
		// Material
		ImGui::Text("Material:");
		renderMaterialSelector(entity, tb);
		
		ImGui::Separator();
		
		// Output mode
		ImGui::Text("Output:");
		if (ImGui::Checkbox("Use StaticGeometry", &tb.useStaticGeometry)) {
			tb.markDirty();
			modified = true;
		}
		
		if (tb.useStaticGeometry) {
			renderStaticGeometrySelector(entity, tb);
		}
		
		ImGui::Separator();
		
		// Rebuild button
		if (ImGui::Button("Force Rebuild")) {
			tb.markDirty();
			modified = true;
		}
		
		ImGui::Separator();
		
		// Info
		ImGui::TextDisabled("Add Primitive components as children to build geometry");
		
		// Count children primitives
		int primCount = 0;
		entity.children([&](flecs::entity child) {
			if (child.has<PrimitiveComponent>()) primCount++;
		});
		ImGui::Text("Child primitives: %d", primCount);
		
		ImGui::Unindent();
	}
	
	return modified;
}
