#include "ActionDebugEditor.hpp"
#include "GoapBlackboardEditor.hpp"
#include "../components/Transform.hpp"
#include "../components/EntityName.hpp"
#include "../systems/SmartObjectSystem.hpp"
#include <imgui.h>

ActionDatabase *ActionDebugEditor::findDatabase(flecs::entity entity)
{
	(void)entity;
	return ActionDatabase::getSingletonPtr();
}

bool ActionDebugEditor::renderComponent(flecs::entity entity,
					ActionDebug &debug)
{
	ImGui::PushID("ActionDebug");
	bool modified = false;

	if (ImGui::CollapsingHeader("Blackboard",
				    ImGuiTreeNodeFlags_DefaultOpen)) {
		modified |= renderBlackboard(debug);
	}

	if (ImGui::CollapsingHeader("Action Tester"))
		renderActionTester(entity, debug);

	if (ImGui::CollapsingHeader("Goal Tester"))
		renderGoalTester(entity, debug);

	if (ImGui::CollapsingHeader("Smart Object Tester",
				    ImGuiTreeNodeFlags_DefaultOpen))
		renderSmartObjectTester(entity, debug);

	if (ImGui::CollapsingHeader("Planner",
				    ImGuiTreeNodeFlags_DefaultOpen))
		renderPlanner(entity, debug);

	if (!debug.lastResult.empty()) {
		ImGui::Separator();
		ImGui::Text("Last result: %s", debug.lastResult.c_str());
	}

	ImGui::PopID();
	return modified;
}

bool ActionDebugEditor::renderBlackboard(ActionDebug &debug)
{
	return GoapBlackboardEditor::render(debug.blackboard, "debugBB");
}

void ActionDebugEditor::renderActionTester(flecs::entity entity,
					   ActionDebug &debug)
{
	ActionDatabase *db = findDatabase(entity);
	if (!db) {
		ImGui::TextDisabled("No ActionDatabase found in scene.");
		return;
	}

	ImGui::Text("Available Actions:");
	ImGui::Indent();

	for (const auto &action : db->actions) {
		bool canRun = action.canRun(debug.blackboard);
		ImGui::PushID(action.name.c_str());

		if (!canRun)
			ImGui::BeginDisabled();

		if (ImGui::Button("Run")) {
			debug.selectedActionName = action.name;
			debug.isRunning = true;
			debug.runTimer = 0.0f;
			debug.currentActionName = action.name;
			// Apply effects to local blackboard for testing
			debug.blackboard.apply(action.effects);
			debug.lastResult =
				"Ran " + action.name + " (cost: " +
				Ogre::StringConverter::toString(action.cost) +
				")";
		}

		if (!canRun)
			ImGui::EndDisabled();

		ImGui::SameLine();
		ImGui::Text("%s (cost: %d) %s", action.name.c_str(),
			    action.cost, canRun ? "" : "[blocked]");

		ImGui::PopID();
	}

	ImGui::Unindent();

	if (debug.isRunning) {
		ImGui::Text("Running: %s (%.1fs)",
			    debug.currentActionName.c_str(), debug.runTimer);
		ImGui::SameLine();
		if (ImGui::SmallButton("Stop")) {
			debug.isRunning = false;
			debug.runTimer = 0.0f;
		}
	}
}

void ActionDebugEditor::renderGoalTester(flecs::entity entity,
					 ActionDebug &debug)
{
	ActionDatabase *db = findDatabase(entity);
	if (!db) {
		ImGui::TextDisabled("No ActionDatabase found in scene.");
		return;
	}

	const GoapGoal *bestGoal = db->selectBestGoal(debug.blackboard);

	ImGui::Text("Best Valid Goal: %s",
		    bestGoal ? bestGoal->name.c_str() : "(none)");

	ImGui::Separator();
	ImGui::Text("All Goals:");
	ImGui::Indent();

	for (const auto &goal : db->goals) {
		bool valid = goal.isValid(debug.blackboard);
		bool satisfied = goal.isSatisfied(debug.blackboard);

		ImGui::PushID(goal.name.c_str());

		ImGui::Text("%s (prio: %d) %s", goal.name.c_str(),
			    goal.priority,
			    satisfied ? "[satisfied]" :
					(valid ? "[valid]" : "[invalid]"));

		if (!goal.condition.empty()) {
			ImGui::SameLine();
			ImGui::TextDisabled("cond: %s", goal.condition.c_str());
		}

		ImGui::PopID();
	}

	ImGui::Unindent();
}


void ActionDebugEditor::renderSmartObjectTester(flecs::entity entity,
						ActionDebug &debug)
{
	auto world = entity.world();

	// Find SmartObjectSystem instance
	SmartObjectSystem *soSystem = SmartObjectSystem::getInstance();
	if (!soSystem) {
		ImGui::TextDisabled("SmartObjectSystem not available.");
		return;
	}

	ImGui::Text("Smart Objects in Scene:");
	ImGui::Indent();

	// Query all entities with SmartObjectComponent
	bool foundAny = false;
	world.query<SmartObjectComponent, TransformComponent>().each(
		[&](flecs::entity so, SmartObjectComponent &soComp,
		    TransformComponent &soTrans) {
			(void)soTrans;
			foundAny = true;

			// Get entity name
			Ogre::String name =
				"Entity " +
				Ogre::StringConverter::toString(so.id());
			if (so.has<EntityNameComponent>()) {
				name = so.get<EntityNameComponent>().name;
			}

			ImGui::PushID(so.id());
			ImGui::Text("%s", name.c_str());
			ImGui::SameLine();
			ImGui::TextDisabled("(r=%.1f, h=%.1f, %zu actions)",
					    soComp.radius, soComp.height,
					    soComp.actionNames.size());

			// Show available actions for this smart object
			ImGui::Indent();
			for (const auto &actionName : soComp.actionNames) {
				ImGui::PushID(actionName.c_str());
				ImGui::Text("%s", actionName.c_str());
				ImGui::SameLine();
				if (ImGui::SmallButton("Test on Character")) {
					bool ok =
						soSystem->testSmartObjectAction(
							entity, so, actionName);
					if (ok) {
						debug.lastResult =
							"Testing smart object action '" +
							actionName + "' on " +
							name;
					} else {
						debug.lastResult =
							"Failed to start smart object action '" +
							actionName + "'";
					}
				}
				ImGui::PopID();
			}
			ImGui::Unindent();
			ImGui::PopID();
		});

	if (!foundAny) {
		ImGui::TextDisabled("No smart objects in scene.");
	}

	ImGui::Unindent();
}

void ActionDebugEditor::renderPlanner(flecs::entity entity,
					      ActionDebug &debug)
{
	(void)debug;

	if (!entity.has<GoapPlannerComponent>()) {
		ImGui::TextDisabled(
			"No GoapPlannerComponent found on this entity.");
		return;
	}

	auto &planner = entity.get_mut<GoapPlannerComponent>();

	// Status
	const char *statusStr = "Idle";
	ImVec4 statusColor(0.7f, 0.7f, 0.7f, 1.0f);
	switch (planner.status) {
	case GoapPlannerComponent::Status::Idle:
		statusStr = "Idle";
		break;
	case GoapPlannerComponent::Status::Planning:
		statusStr = "Planning...";
		statusColor = ImVec4(1.0f, 0.8f, 0.2f, 1.0f);
		break;
	case GoapPlannerComponent::Status::PlansAvailable:
		statusStr = "Plans Available";
		statusColor = ImVec4(0.3f, 1.0f, 0.3f, 1.0f);
		break;
	case GoapPlannerComponent::Status::NoPlanFound:
		statusStr = "No Plan Found";
		statusColor = ImVec4(1.0f, 0.3f, 0.3f, 1.0f);
		break;
	}
	ImGui::Text("Status: ");
	ImGui::SameLine();
	ImGui::TextColored(statusColor, "%s", statusStr);

	if (planner.status == GoapPlannerComponent::Status::Planning) {
		ImGui::Text("Nodes explored: %d",
			    planner.nodesExplored);
	}

	if (!planner.currentGoalName.empty()) {
		ImGui::Text("Current Goal: %s",
			    planner.currentGoalName.c_str());
	}

	ImGui::Separator();

	// Display plan queue
	if (planner.planQueue.empty()) {
		ImGui::TextDisabled("No plans in queue.");
	} else {
		ImGui::Text("Plan Queue (%zu plans):",
			    planner.planQueue.size());
		ImGui::Indent();

		ActionDatabase *db = findDatabase(entity);

		for (int p = 0; p < (int)planner.planQueue.size(); p++) {
			const auto &plan = planner.planQueue[p];
			ImGui::Text("Plan %d (cost: %d, goal: %s):",
				    p + 1, plan.totalCost,
				    plan.goalName.c_str());
			ImGui::Indent();
			for (int i = 0;
			     i < (int)plan.actions.size(); i++) {
				const auto &actionName = plan.actions[i];
				bool isSmartObjectAction = false;
				if (db) {
					const GoapAction *action =
						db->findAction(actionName);
					if (!action)
						isSmartObjectAction = true;
				}
				if (isSmartObjectAction) {
					ImGui::TextColored(
						ImVec4(0.3f, 0.8f, 1.0f,
						       1.0f),
						"%d. %s [SO]", i + 1,
						actionName.c_str());
				} else {
					ImGui::Text("%d. %s", i + 1,
						actionName.c_str());
				}
			}
			ImGui::Unindent();
		}

		ImGui::Unindent();
	}

	ImGui::Separator();

	// Trigger replan button
	if (ImGui::Button("Force Replan")) {
		planner.planDirty = true;
	}

	// Show selected planner actions
	ImGui::Separator();
	ImGui::Text("Planner Action Pool (%zu):",
		    planner.actionNames.size());
	ImGui::Indent();
	for (const auto &name : planner.actionNames) {
		ImGui::Text("%s", name.c_str());
	}
	ImGui::Unindent();
}
