#include "GoapBlackboardEditor.hpp"
#include <imgui.h>
#include <cstring>

bool GoapBlackboardEditor::render(GoapBlackboard &bb, const char *id)
{
	bool changed = false;
	ImGui::PushID(id);

	if (ImGui::TreeNode("Bits")) {
		changed |= renderBits(bb, id);
		ImGui::TreePop();
	}

	if (ImGui::TreeNode("Int Values")) {
		changed |= renderIntValues(bb, id);
		ImGui::TreePop();
	}

	if (ImGui::TreeNode("Float Values")) {
		changed |= renderFloatValues(bb, id);
		ImGui::TreePop();
	}

	if (ImGui::TreeNode("Vec3 Values")) {
		changed |= renderVec3Values(bb, id);
		ImGui::TreePop();
	}

	ImGui::PopID();
	return changed;
}

bool GoapBlackboardEditor::renderBits(GoapBlackboard &bb, const char *id)
{
	(void)id;
	bool changed = false;

	for (int row = 0; row < 8; row++) {
		for (int col = 0; col < 8; col++) {
			int bitIndex = row * 8 + col;
			bool has = bb.hasBit(bitIndex);
			bool val = bb.getBit(bitIndex);

			ImGui::PushID(bitIndex);

			ImU32 color = has ? (val ? IM_COL32(100, 255, 100, 255)
						 : IM_COL32(255, 100, 100, 255))
					  : IM_COL32(80, 80, 80, 255);

			const char *bitName = GoapBlackboard::getBitName(bitIndex);
			char label[32];
			if (bitName)
				snprintf(label, sizeof(label), "%s", bitName);
			else
				snprintf(label, sizeof(label), "%d", bitIndex);

			ImGui::PushStyleColor(ImGuiCol_Button, color);
			if (ImGui::SmallButton(label)) {
				if (!has) {
					bb.setBit(bitIndex, true);
				} else if (!val) {
					bb.setBit(bitIndex, true);
				} else {
					bb.clearBit(bitIndex);
				}
				changed = true;
			}
			ImGui::PopStyleColor();

			if (ImGui::IsItemHovered()) {
				if (bitName)
					ImGui::SetTooltip("Bit %d: %s = %s", bitIndex,
							  bitName,
							  has ? (val ? "true" : "false")
							      : "unset");
				else
					ImGui::SetTooltip("Bit %d = %s", bitIndex,
							  has ? (val ? "true" : "false")
							      : "unset");
			}

			if (col < 7)
				ImGui::SameLine();

			ImGui::PopID();
		}
	}

	ImGui::Text("Mask: 0x%016llX  Bits: 0x%016llX",
		    (unsigned long long)bb.mask, (unsigned long long)bb.bits);

	return changed;
}

bool GoapBlackboardEditor::renderIntValues(GoapBlackboard &bb, const char *id)
{
	(void)id;
	bool changed = false;
	static char newKey[256] = "";
	static int newValue = 0;

	std::vector<std::string> keysToRemove;
	for (auto &pair : bb.values) {
		ImGui::PushID(pair.first.c_str());
		int val = pair.second;
		if (ImGui::InputInt(pair.first.c_str(), &val)) {
			pair.second = val;
			changed = true;
		}
		ImGui::SameLine();
		if (ImGui::SmallButton("X"))
			keysToRemove.push_back(pair.first);
		ImGui::PopID();
	}
	for (const auto &key : keysToRemove)
		bb.values.erase(key);

	ImGui::Separator();
	ImGui::InputText("New Key", newKey, sizeof(newKey));
	ImGui::InputInt("New Value", &newValue);
	ImGui::SameLine();
	if (ImGui::Button("Add") && newKey[0] != 0) {
		bb.setValue(newKey, newValue);
		newKey[0] = 0;
		newValue = 0;
		changed = true;
	}

	return changed;
}

bool GoapBlackboardEditor::renderFloatValues(GoapBlackboard &bb, const char *id)
{
	(void)id;
	bool changed = false;
	static char newKey[256] = "";
	static float newValue = 0.0f;

	std::vector<std::string> keysToRemove;
	for (auto &pair : bb.floatValues) {
		ImGui::PushID(pair.first.c_str());
		float val = pair.second;
		if (ImGui::InputFloat(pair.first.c_str(), &val)) {
			pair.second = val;
			changed = true;
		}
		ImGui::SameLine();
		if (ImGui::SmallButton("X"))
			keysToRemove.push_back(pair.first);
		ImGui::PopID();
	}
	for (const auto &key : keysToRemove)
		bb.floatValues.erase(key);

	ImGui::Separator();
	ImGui::InputText("New Key", newKey, sizeof(newKey));
	ImGui::InputFloat("New Value", &newValue);
	ImGui::SameLine();
	if (ImGui::Button("Add") && newKey[0] != 0) {
		bb.setFloatValue(newKey, newValue);
		newKey[0] = 0;
		newValue = 0.0f;
		changed = true;
	}

	return changed;
}

bool GoapBlackboardEditor::renderVec3Values(GoapBlackboard &bb, const char *id)
{
	(void)id;
	bool changed = false;
	static char newKey[256] = "";
	static float newV[3] = { 0.0f, 0.0f, 0.0f };

	std::vector<std::string> keysToRemove;
	for (auto &pair : bb.vec3Values) {
		ImGui::PushID(pair.first.c_str());
		float v[3] = { pair.second.x, pair.second.y, pair.second.z };
		if (ImGui::InputFloat3(pair.first.c_str(), v)) {
			pair.second = Ogre::Vector3(v[0], v[1], v[2]);
			changed = true;
		}
		ImGui::SameLine();
		if (ImGui::SmallButton("X"))
			keysToRemove.push_back(pair.first);
		ImGui::PopID();
	}
	for (const auto &key : keysToRemove)
		bb.vec3Values.erase(key);

	ImGui::Separator();
	ImGui::InputText("New Key", newKey, sizeof(newKey));
	ImGui::InputFloat3("New Value", newV);
	ImGui::SameLine();
	if (ImGui::Button("Add") && newKey[0] != 0) {
		bb.setVec3Value(newKey, Ogre::Vector3(newV[0], newV[1], newV[2]));
		newKey[0] = 0;
		newV[0] = 0.0f;
		newV[1] = 0.0f;
		newV[2] = 0.0f;
		changed = true;
	}

	return changed;
}
