#include "ProceduralTextureEditor.hpp"
#include "../components/ProceduralTexture.hpp"
#include <imgui.h>
#include <OgreColourValue.h>
#include <OgreTextureManager.h>
#include <OgreImage.h>
#include <OgreLogManager.h>

void ProceduralTextureEditor::renderColorButton(
	int index, ProceduralTextureComponent &texture)
{
	Ogre::ColourValue color = texture.getColor(index);

	// Create a unique ID for this button
	ImGui::PushID(index);

	// Show color as a small colored button
	ImVec4 buttonColor(color.r, color.g, color.b, color.a);
	ImGui::ColorButton("##color", buttonColor,
			   ImGuiColorEditFlags_NoTooltip, ImVec2(24, 24));

	// Handle click
	if (ImGui::IsItemClicked()) {
		m_selectedRect = index;
	}

	// Show tooltip with rectangle index
	if (ImGui::IsItemHovered()) {
		ImGui::SetTooltip("Rect %d: (%.2f, %.2f, %.2f)", index, color.r,
				  color.g, color.b);
	}

	ImGui::PopID();
}

void ProceduralTextureEditor::renderColorGrid(
	flecs::entity entity, ProceduralTextureComponent &texture)
{
	const int gridSize = ProceduralTextureComponent::GRID_SIZE;

	ImGui::Text(
		"10x10 Grid - Click a rectangle to edit its color or add to atlas:");

	// Calculate grid width for centering
	float buttonSize = 24.0f;
	float spacing = 2.0f;
	float gridWidth = gridSize * buttonSize + (gridSize - 1) * spacing;

	// Get window width for centering
	float windowWidth = ImGui::GetContentRegionAvail().x;
	float startX = ImGui::GetCursorPosX();
	float offset = (windowWidth - gridWidth) * 0.5f;
	if (offset < 0)
		offset = 0;

	// Render the grid - each row needs its own offset
	for (int row = 0; row < gridSize; ++row) {
		// Set cursor position for this row
		ImGui::SetCursorPosX(startX + offset);

		for (int col = 0; col < gridSize; ++col) {
			int index = row * gridSize + col;
			renderColorButton(index, texture);

			if (col < gridSize - 1) {
				ImGui::SameLine(0, spacing);
			}
		}
	}

	// Color picker and naming for selected rectangle
	if (m_selectedRect >= 0 &&
	    m_selectedRect < ProceduralTextureComponent::RECT_COUNT) {
		ImGui::Separator();
		ImGui::Text("Editing Rectangle %d (Row %d, Col %d)",
			    m_selectedRect, m_selectedRect / gridSize,
			    m_selectedRect % gridSize);

		// UV coordinates display
		float u1, v1, u2, v2;
		texture.getRectUVs(m_selectedRect, u1, v1, u2, v2);
		ImGui::TextDisabled("UVs: (%.3f, %.3f) - (%.3f, %.3f)", u1, v1,
				    u2, v2);

		Ogre::ColourValue currentColor =
			texture.getColor(m_selectedRect);
		float colorArray[4] = { currentColor.r, currentColor.g,
					currentColor.b, currentColor.a };

		if (ImGui::ColorEdit4("Color", colorArray)) {
			Ogre::ColourValue newColor(colorArray[0], colorArray[1],
						   colorArray[2],
						   colorArray[3]);
			texture.setColor(m_selectedRect, newColor);
		}

		// Add to atlas section
		ImGui::Separator();
		ImGui::Text("Add to Texture Atlas:");

		ImGui::InputText("Name", m_nameBuffer, sizeof(m_nameBuffer));
		ImGui::SameLine();

		if (ImGui::Button("Add")) {
			if (strlen(m_nameBuffer) > 0) {
				if (texture.hasNamedRect(m_nameBuffer)) {
					ImGui::TextColored(
						ImVec4(1, 0, 0, 1),
						"Name already exists!");
				} else {
					texture.addNamedRect(m_nameBuffer,
							     m_selectedRect);
					m_nameBuffer[0] = '\0'; // Clear buffer
				}
			}
		}

		if (ImGui::Button("Deselect")) {
			m_selectedRect = -1;
			m_nameBuffer[0] = '\0';
		}

		ImGui::SameLine();

		// Preset colors
		ImGui::Text("Presets:");
		ImGui::SameLine();

		const ImVec4 presets[] = {
			ImVec4(1, 1, 1, 1), // White
			ImVec4(0, 0, 0, 1), // Black
			ImVec4(1, 0, 0, 1), // Red
			ImVec4(0, 1, 0, 1), // Green
			ImVec4(0, 0, 1, 1), // Blue
			ImVec4(1, 1, 0, 1), // Yellow
			ImVec4(1, 0, 1, 1), // Magenta
			ImVec4(0, 1, 1, 1), // Cyan
			ImVec4(0.5f, 0.5f, 0.5f, 1), // Gray
		};

		for (size_t i = 0; i < IM_ARRAYSIZE(presets); ++i) {
			ImGui::PushID((int)i);
			if (ImGui::ColorButton("##preset", presets[i],
					       ImGuiColorEditFlags_NoTooltip,
					       ImVec2(20, 20))) {
				Ogre::ColourValue presetColor(presets[i].x,
							      presets[i].y,
							      presets[i].z,
							      presets[i].w);
				texture.setColor(m_selectedRect, presetColor);
			}
			ImGui::PopID();
			if (i < IM_ARRAYSIZE(presets) - 1) {
				ImGui::SameLine(0, 2);
			}
		}
	}
}

void ProceduralTextureEditor::renderNamedRects(
	flecs::entity entity, ProceduralTextureComponent &texture)
{
	ImGui::Separator();
	ImGui::Text("Texture Atlas (Named Rectangles):");

	const auto &namedRects = texture.getAllNamedRects();

	if (namedRects.empty()) {
		ImGui::TextDisabled(
			"No named rectangles. Select a rectangle above and add it to the atlas.");
	} else {
		// Table header
		if (ImGui::BeginTable("NamedRects", 3,
				      ImGuiTableFlags_Borders |
					      ImGuiTableFlags_RowBg)) {
			ImGui::TableSetupColumn("Name");
			ImGui::TableSetupColumn("UV Coordinates");
			ImGui::TableSetupColumn("Action");
			ImGui::TableHeadersRow();

			for (const auto &pair : namedRects) {
				const auto &rect = pair.second;
				ImGui::TableNextRow();

				// Name column
				ImGui::TableNextColumn();
				ImGui::Text("%s", rect.name.c_str());

				// UVs column
				ImGui::TableNextColumn();
				ImGui::Text("(%.3f, %.3f) - (%.3f, %.3f)",
					    rect.u1, rect.v1, rect.u2, rect.v2);

				// Action column
				ImGui::TableNextColumn();
				ImGui::PushID(rect.name.c_str());
				if (ImGui::Button("Delete")) {
					texture.removeNamedRect(rect.name);
				}
				ImGui::PopID();
			}

			ImGui::EndTable();
		}

		ImGui::TextDisabled("Total: %zu named rectangles",
				    namedRects.size());
	}
}

bool ProceduralTextureEditor::renderComponent(
	flecs::entity entity, ProceduralTextureComponent &texture)
{
	bool modified = false;

	if (ImGui::CollapsingHeader("Procedural Texture",
				    ImGuiTreeNodeFlags_DefaultOpen)) {
		ImGui::Indent();

		// Texture info
		if (texture.generated) {
			ImGui::TextColored(ImVec4(0, 1, 0, 1),
					   "Status: Generated");
			ImGui::Text("Texture: %s", texture.textureName.c_str());
			ImGui::Text("Size: %dx%d", texture.textureSize,
				    texture.textureSize);

			// Save PNG button
			if (ImGui::Button("Save as PNG...")) {
				ImGui::OpenPopup("SaveTexturePopup");
			}

			// Save popup
			if (ImGui::BeginPopup("SaveTexturePopup")) {
				static char filename[256] =
					"procedural_texture.png";
				ImGui::InputText("Filename", filename,
						 sizeof(filename));

				if (ImGui::Button("Save", ImVec2(120, 0))) {
					try {
						if (texture.ogreTexture) {
							Ogre::Image image;
							texture.ogreTexture
								->convertToImage(
									image);
							image.save(filename);
							Ogre::LogManager::getSingleton()
								.logMessage(
									"ProceduralTexture: Saved to " +
									std::string(
										filename));
						}
					} catch (const Ogre::Exception &e) {
						Ogre::LogManager::getSingleton().logMessage(
							"ProceduralTexture ERROR: Failed to save: " +
							e.getDescription());
					}
					ImGui::CloseCurrentPopup();
				}
				ImGui::SameLine();
				if (ImGui::Button("Cancel", ImVec2(120, 0))) {
					ImGui::CloseCurrentPopup();
				}
				ImGui::EndPopup();
			}
		} else if (texture.dirty) {
			ImGui::TextColored(ImVec4(1, 1, 0, 1),
					   "Status: Needs Generation");
		} else {
			ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1),
					   "Status: Not Generated");
		}

		ImGui::Separator();

		// Texture size selector
		const int sizes[] = { 128, 256, 512, 1024, 2048 };
		int currentSizeIndex = 2; // Default 512
		for (int i = 0; i < IM_ARRAYSIZE(sizes); ++i) {
			if (sizes[i] == texture.textureSize) {
				currentSizeIndex = i;
				break;
			}
		}

		const char *sizeNames[] = { "128x128", "256x256", "512x512",
					    "1024x1024", "2048x2048" };
		if (ImGui::Combo("Texture Size", &currentSizeIndex, sizeNames,
				 IM_ARRAYSIZE(sizeNames))) {
			texture.textureSize = sizes[currentSizeIndex];
			texture.markDirty();
			modified = true;
		}

		// UV Margin control to prevent color bleeding
		ImGui::Separator();
		ImGui::Text("UV Margin (prevents color bleeding):");
		if (ImGui::DragFloat("Margin", &texture.uvMargin, 0.001f, 0.01f,
				     0.035f, "%.3f")) {
			// Clamp to valid range
			if (texture.uvMargin < 0.01f)
				texture.uvMargin = 0.01f;
			if (texture.uvMargin > 0.035f)
				texture.uvMargin = 0.035f;
			texture.markDirty();
			modified = true;
		}
		ImGui::TextDisabled(
			"Default: 0.010, Range: 0.010-0.035, Step: 0.001");
		ImGui::TextDisabled(
			"Higher values = more padding, less color bleeding");

		ImGui::Separator();

		// Color grid
		renderColorGrid(entity, texture);

		// Named rectangles list
		renderNamedRects(entity, texture);

		ImGui::Separator();

		// Global actions
		if (ImGui::Button("Randomize Colors")) {
			for (int i = 0;
			     i < ProceduralTextureComponent::RECT_COUNT; ++i) {
				Ogre::ColourValue randomColor(
					(float)rand() / RAND_MAX,
					(float)rand() / RAND_MAX,
					(float)rand() / RAND_MAX, 1.0f);
				texture.setColor(i, randomColor);
			}
			modified = true;
		}

		ImGui::SameLine();

		if (ImGui::Button("Reset to Checkerboard")) {
			for (int i = 0;
			     i < ProceduralTextureComponent::RECT_COUNT; ++i) {
				int row = i /
					  ProceduralTextureComponent::GRID_SIZE;
				int col = i %
					  ProceduralTextureComponent::GRID_SIZE;
				bool isWhite = (row + col) % 2 == 0;
				Ogre::ColourValue color(isWhite ? 1.0f : 0.0f,
							isWhite ? 1.0f : 0.0f,
							isWhite ? 1.0f : 0.0f,
							1.0f);
				texture.setColor(i, color);
			}
			modified = true;
		}

		ImGui::SameLine();

		if (ImGui::Button("All White")) {
			for (int i = 0;
			     i < ProceduralTextureComponent::RECT_COUNT; ++i) {
				texture.setColor(i, Ogre::ColourValue::White);
			}
			modified = true;
		}

		ImGui::Unindent();
	}

	return modified;
}
