#include "GoapPlannerEditor.hpp"
#include "../components/EntityName.hpp"
#include <imgui.h>

ActionDatabase *GoapPlannerEditor::findDatabase(
	flecs::entity entity, GoapPlannerComponent &planner)
{
	(void)entity;
	(void)planner;
	return ActionDatabase::getSingletonPtr();
}

bool GoapPlannerEditor::renderComponent(flecs::entity entity,
					GoapPlannerComponent &planner)
{
	bool modified = false;
	ImGui::PushID("GoapPlanner");

	// External ActionDatabase reference
	char refBuf[256];
	snprintf(refBuf, sizeof(refBuf), "%s",
		 planner.actionDatabaseRef.c_str());
	if (ImGui::InputText("Action Database Ref", refBuf,
			     sizeof(refBuf))) {
		planner.actionDatabaseRef = refBuf;
		modified = true;
	}
	if (ImGui::IsItemHovered()) {
		ImGui::SetTooltip(
			"Name of the entity that owns the ActionDatabase. "
			"Used to resolve action and goal names when editing prefabs.");
	}

	ImGui::Separator();

	// Smart object settings
	if (ImGui::DragFloat("Smart Object Distance",
			     &planner.smartObjectDistance, 0.5f,
			     1.0f, 500.0f)) {
		modified = true;
	}
	if (ImGui::IsItemHovered()) {
		ImGui::SetTooltip(
			"Maximum distance to search for smart objects "
			"with matching actions");
	}

	if (ImGui::Checkbox("Include Smart Objects",
			    &planner.includeSmartObjects)) {
		modified = true;
	}

	ImGui::Separator();

	// Action and Goal selectors
	ActionDatabase *db = findDatabase(entity, planner);
	renderActionSelector(planner, db);

	ImGui::Separator();

	renderGoalSelector(planner, db);

	ImGui::PopID();
	return modified;
}

void GoapPlannerEditor::renderActionSelector(
	GoapPlannerComponent &planner, ActionDatabase *db)
{
	ImGui::Text("Selected Actions (%zu):",
		    planner.actionNames.size());

	// Show currently selected actions with remove buttons
	int removeIdx = -1;
	for (int i = 0; i < (int)planner.actionNames.size(); i++) {
		ImGui::PushID(i);
		ImGui::Text("%s", planner.actionNames[i].c_str());
		ImGui::SameLine();
		if (ImGui::SmallButton("X")) {
			removeIdx = i;
		}
		ImGui::PopID();
	}
	if (removeIdx >= 0) {
		planner.actionNames.erase(
			planner.actionNames.begin() + removeIdx);
		planner.planDirty = true;
	}

	if (planner.actionNames.empty()) {
		ImGui::TextDisabled("No actions selected");
	}

	ImGui::Separator();

	// Add actions from database
	if (!db) {
		ImGui::TextDisabled(
			"No ActionDatabase found. Add actions manually:");
		static char manualAction[256] = { 0 };
		if (ImGui::InputText("Action Name", manualAction,
				     sizeof(manualAction),
				     ImGuiInputTextFlags_EnterReturnsTrue)) {
			if (manualAction[0] != '\0') {
				planner.actionNames.push_back(manualAction);
				planner.planDirty = true;
				manualAction[0] = '\0';
			}
		}
		return;
	}

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

	for (const auto &action : db->actions) {
		bool alreadySelected = false;
		for (const auto &name : planner.actionNames) {
			if (name == action.name) {
				alreadySelected = true;
				break;
			}
		}

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

		if (alreadySelected) {
			ImGui::BeginDisabled();
		}

		if (ImGui::Button("+")) {
			planner.actionNames.push_back(action.name);
			planner.planDirty = true;
		}

		if (alreadySelected) {
			ImGui::EndDisabled();
		}

		ImGui::SameLine();
		ImGui::Text("%s (cost: %d)", action.name.c_str(),
			    action.cost);

		ImGui::PopID();
	}

	ImGui::Unindent();
}

void GoapPlannerEditor::renderGoalSelector(
	GoapPlannerComponent &planner, ActionDatabase *db)
{
	ImGui::Text("Selected Goals (%zu):",
		    planner.goalNames.size());

	// Show currently selected goals with remove buttons
	int removeIdx = -1;
	for (int i = 0; i < (int)planner.goalNames.size(); i++) {
		ImGui::PushID(i + 10000);
		ImGui::Text("%s", planner.goalNames[i].c_str());
		ImGui::SameLine();
		if (ImGui::SmallButton("X")) {
			removeIdx = i;
		}
		ImGui::PopID();
	}
	if (removeIdx >= 0) {
		planner.goalNames.erase(
			planner.goalNames.begin() + removeIdx);
		planner.planDirty = true;
	}

	if (planner.goalNames.empty()) {
		ImGui::TextDisabled("No goals selected");
	}

	ImGui::Separator();

	// Add goals from database
	if (!db) {
		ImGui::TextDisabled(
			"No ActionDatabase found. Add goals manually:");
		static char manualGoal[256] = { 0 };
		if (ImGui::InputText("Goal Name", manualGoal,
				     sizeof(manualGoal),
				     ImGuiInputTextFlags_EnterReturnsTrue)) {
			if (manualGoal[0] != '\0') {
				planner.goalNames.push_back(manualGoal);
				planner.planDirty = true;
				manualGoal[0] = '\0';
			}
		}
		return;
	}

	ImGui::Text("Available Goals from Database:");
	ImGui::Indent();

	for (const auto &goal : db->goals) {
		bool alreadySelected = false;
		for (const auto &name : planner.goalNames) {
			if (name == goal.name) {
				alreadySelected = true;
				break;
			}
		}

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

		if (alreadySelected) {
			ImGui::BeginDisabled();
		}

		if (ImGui::Button("+")) {
			planner.goalNames.push_back(goal.name);
			planner.planDirty = true;
		}

		if (alreadySelected) {
			ImGui::EndDisabled();
		}

		ImGui::SameLine();
		ImGui::Text("%s (prio: %d)", goal.name.c_str(),
			    goal.priority);

		ImGui::PopID();
	}

	ImGui::Unindent();
}

void GoapPlannerEditor::renderPreconditionMaskEditor(
	GoapAction &action)
{
	ImGui::Separator();
	ImGui::Text("Precondition Mask (bit filter)");
	ImGui::TextDisabled(
		"Only bits set here are checked during planning.");

	for (int i = 0; i < 64; i += 8) {
		for (int j = 0; j < 8 && (i + j) < 64; j++) {
			int bit = i + j;
			bool enabled = (action.preconditionMask >>
					bit) & 1ULL;
			char label[8];
			snprintf(label, sizeof(label), "%d", bit);
			if (j > 0)
				ImGui::SameLine();
			if (ImGui::Checkbox(label, &enabled)) {
				if (enabled)
					action.preconditionMask |= (1ULL << bit);
				else
					action.preconditionMask &=
						~(1ULL << bit);
			}
		}
	}

	ImGui::Text("Mask: 0x%016llX",
		    (unsigned long long)action.preconditionMask);
	ImGui::SameLine();
	if (ImGui::SmallButton("Set All")) {
		action.preconditionMask = ~0ULL;
	}
	ImGui::SameLine();
	if (ImGui::SmallButton("Clear All")) {
		action.preconditionMask = 0ULL;
	}
}
