#include <iostream>
#include <OgreOverlaySystem.h>
#include <OgreOverlayManager.h>
#include <OgreImGuiOverlay.h>
#include <OgreImGuiInputListener.h>
#include <OgreRenderTargetListener.h>
#include <OgreSceneNode.h>
#include <OgreApplicationContext.h>
#include <OgreImGuiInputListener.h>
#include <OgreFontManager.h>
#include <OgreTerrainGroup.h>
#include <OgrePagedWorld.h>
#include <OgreTerrainPaging.h>
#include <OgreTerrainPagedWorldSection.h>
#include <nlohmann/json.hpp>
#include "GameData.h"
#include "Components.h"
#include "LuaData.h"
#include "AppModule.h"
#include "TerrainModule.h"
#include "StaticGeometryModule.h"
#include "EditorGizmoModule.h"
#include "PhysicsModule.h"
#include "PlayerActionModule.h"
#include "CharacterModule.h"
#include "CharacterManagerModule.h"
#include "items.h"
#include "physics.h"
#include "QuestModule.h"
#include "GUIModule.h"
#include "GUIModuleCommon.h"
#include <tracy/Tracy.hpp>
namespace ECS
{
struct GUIListener;
struct GUIData {
	Ogre::ImGuiOverlay *mGuiOverlay;
	std::vector<Ogre::String> glb_names;
	GUIListener *mGUIListener;
};
struct GUIListener : public Ogre::RenderTargetListener {
	float panel_width;
	bool enableEditor;
	bool enableMapEditor;
	ImFont *smallFont, *midFont, *bigFont;
	Ogre::FontPtr _smallFont, _midFont, _bigFont;
	GUIListener()
		: Ogre::RenderTargetListener()
	{
        ZoneScoped;
		_midFont = createFont("midFont", "General",
				      "Jupiteroid-Regular.ttf", 24.0f);
		_smallFont = createFont("smallFont", "General",
					"Jupiteroid-Regular.ttf", 18.0f);
		_bigFont = createFont("bigFont", "General", "Kenney Bold.ttf",
				      36.0f);
		smallFont = ECS::get<GUIData>().mGuiOverlay->addFont(
			"smallFont", "General");
		OgreAssert(smallFont, "Could not load font");
		midFont = ECS::get<GUIData>().mGuiOverlay->addFont("midFont",
								   "General");
		OgreAssert(midFont, "Could not load font");
		bigFont = ECS::get<GUIData>().mGuiOverlay->addFont("bigFont",
								   "General");
		OgreAssert(bigFont, "Could not load font");
	}
	Ogre::FontPtr createFont(const Ogre::String &name,
				 const Ogre::String &group,
				 const Ogre::String &ttfname, float fontSize)
	{
        ZoneScoped;
        Ogre::FontPtr ret =
			Ogre::FontManager::getSingleton().create(name, group);
		ret->setType(Ogre::FontType::FT_TRUETYPE);
		ret->setSource(ttfname);
		ret->setTrueTypeSize(fontSize);
		ret->setTrueTypeResolution(75);
		ret->addCodePointRange(Ogre::Font::CodePointRange(30, 128));
		ret->load();
		return ret;
	}
	void
	preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override
	{
        ZoneScopedN("GUIModule::preViewportUpdate");
        preview(evt);
	}
	void buttons_panel()
	{
        ZoneScoped;
        bool enableDebugRender = ECS::get<EngineData>().enableDbgDraw;
        ImVec2 size = ImGui::GetMainViewport()->Size;
		float window_width = size.x * 0.2f;
		if (window_width > panel_width)
			window_width = panel_width;
		float window_height = size.y * 0.5f - 20;
		ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.5f + 20),
					ImGuiCond_Always);
		ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
					 ImGuiCond_Always);
		ImGui::Begin("Control");
		if (ImGui::Button("Quit"))
			Ogre::Root::getSingleton().queueEndRendering();
		if (ImGui::Button("Return"))
			ECS::get().get<GUI>().finish();
		if (ImGui::Button("Enable/Disable item editor")) {
			enableEditor ^= true;
			if (enableEditor)
				enableMapEditor = false;
		}
		if (ImGui::Button("Enable/Disable map editor")) {
			enableMapEditor ^= true;
			if (enableMapEditor)
				enableEditor = false;
		}
        if (ImGui::Checkbox("Enable physics debug",
                    &enableDebugRender)) {
            ECS::get_mut<EngineData>().enableDbgDraw =
                enableDebugRender;
            ECS::modified<EngineData>();
            PhysicsModule::setDebugDraw(enableDebugRender);
        }
        ImGui::Text("Text message...");
		ImGui::End();
	}
	void create_entity_node(const Ogre::String &name, int key)
	{
        ZoneScoped;
        Ogre::Entity *ent =
			ECS::get().get<EngineData>().mScnMgr->createEntity(
				name);
		Ogre::SceneNode *pnode =
			ECS::get()
				.get<EngineData>()
				.mScnMgr->getRootSceneNode()
				->createChildSceneNode(
					"ent:" + name +
						Ogre::StringConverter::toString(
							key),
					ECS::get()
						.get<Camera>()
						.mCameraPivot->getPosition(),
					ECS::get()
						.get<Camera>()
						.mCameraPivot->getOrientation());
		pnode->attachObject(ent);
		Ogre::Quaternion q = pnode->getOrientation();
		Ogre::Radian yaw = q.getYaw();
		Ogre::Quaternion nq(yaw, Ogre::Vector3(0, 1, 0));
		pnode->setOrientation(nq);

		ECS::get().get<GUI>().finish();
	}
	void buildings_editor()
	{
        ZoneScoped;
        int i;
		ImVec2 size = ImGui::GetMainViewport()->Size;
		float window_width = size.x * 0.2f;
		if (window_width > panel_width)
			window_width = panel_width;
		float window_height = size.y * 0.5 - 20;
		ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
		ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
					 ImGuiCond_Always);
		ImGui::Begin("Droppings...");
		for (i = 0; i < ECS::get().get<GUIData>().glb_names.size();
		     i++) {
			Ogre::String id_button =
				"Create entity: " +
				ECS::get().get<GUIData>().glb_names[i] +
				"##ent:" +
				ECS::get().get<GUIData>().glb_names[i];
			if (ImGui::Button(id_button.c_str())) {
				create_entity_node(
					ECS::get().get<GUIData>().glb_names[i],
					i);
			}
		}
		ImGui::End();
	}
	void position_editor(Ogre::SceneNode *node)
	{
        ZoneScoped;
        Ogre::Vector3 position = node->getPosition();
		float v[3] = { position.x, position.y, position.z };
		ImGui::InputFloat3("position", v);
		position.x = v[0];
		position.y = v[1];
		position.z = v[2];
		node->setPosition(position);
	}
	void orientation_editor(Ogre::SceneNode *node)
	{
        ZoneScoped;
        Ogre::Quaternion q = node->getOrientation();
		float yaw = Ogre::Radian(q.getYaw()).valueDegrees();
		float pitch = Ogre::Radian(q.getPitch()).valueDegrees();
		float roll = Ogre::Radian(q.getRoll()).valueDegrees();
		bool m1 = ImGui::InputFloat("yaw", &yaw);
		bool m2 = ImGui::InputFloat("pitch", &pitch);
		bool m3 = ImGui::InputFloat("roll", &roll);
		if (m1 || m2 || m3) {
			Ogre::Quaternion q1(Ogre::Radian(Ogre::Degree(yaw)),
					    Ogre::Vector3::UNIT_Y);
			Ogre::Quaternion q2(Ogre::Degree(pitch),
					    Ogre::Vector3::UNIT_X);
			Ogre::Quaternion q3(Ogre::Degree(roll),
					    Ogre::Vector3::UNIT_Z);
			node->setOrientation(q1 * q2 * q3);
		}
	}
	void attachments_editor(Ogre::SceneNode *node)
	{
        ZoneScoped;
        const Ogre::SceneNode::ObjectMap &pmap =
			node->getAttachedObjects();
		int i;
		for (i = 0; i < pmap.size(); i++) {
			const Ogre::MovableObject *mobj = pmap[i];
			const Ogre::String &pname = mobj->getName();
			ImGui::Text("Name: %s", pname.c_str());
		}
	}
	void map_editor()
	{
	}
    Ogre::Vector2 projectToScreen(const Ogre::Vector3 &worldPoint)
    {
        ZoneScoped;
        ImVec2 size = ImGui::GetMainViewport()->Size;
        float width = size.x;
        float height = size.y;
        Ogre::Camera *camera = ECS::get<Camera>().mCamera;
        // 1. Convert to camera space (OGRE camera looks down -Z)
        Ogre::Vector3 eyeSpacePoint =
            camera->getViewMatrix() * worldPoint;
        if (eyeSpacePoint.z >= 0.0f)
            return Ogre::Vector2(-1, -1);

        // 2. Project to homogeneous clip space using Vector4 to preserve W
        Ogre::Vector4 clipSpacePoint =
            camera->getProjectionMatrix() *
            Ogre::Vector4(eyeSpacePoint.x, eyeSpacePoint.y,
                          eyeSpacePoint.z, 1.0f);
        if (clipSpacePoint.w <= 0.0f)
            return Ogre::Vector2(-1, -1);

        // 3. Perspective divide to get NDC [-1, 1]
        float ndcX = clipSpacePoint.x / clipSpacePoint.w;
        float ndcY = clipSpacePoint.y / clipSpacePoint.w;

        // 4. Convert NDC to screen space [0, 1], flipping Y for ImGui
        float screenX = (ndcX * 0.5f) + 0.5f;
        float screenY = 1.0f - ((ndcY * 0.5f) + 0.5f);

        // 5. Reject if outside viewport bounds
        if (screenX < 0.0f || screenX > 1.0f ||
            screenY < 0.0f || screenY > 1.0f)
            return Ogre::Vector2(-1, -1);

        // 6. Map to actual pixel dimensions
        return Ogre::Vector2(screenX * width, screenY * height);
    }
    void preview(const Ogre::RenderTargetViewportEvent &evt)
	{
        ZoneScoped;
        int i;
		Ogre::ImGuiOverlay::NewFrame();

        if (ECS::get().get<EngineData>().startupDelay > 0.0f &&
            ECS::get().has<GameState>()) {
			ImVec2 size = ImGui::GetMainViewport()->Size;
			ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
			ImGui::SetNextWindowSize(ImVec2(size.x, size.y),
						 ImGuiCond_Always);
            ImVec4 solidColor = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
            ImGui::PushStyleColor(ImGuiCol_WindowBg, solidColor);
			ImGui::Begin(
				"StartupScreen", nullptr,
				ImGuiWindowFlags_NoTitleBar |
					ImGuiWindowFlags_NoDecoration |

					ImGuiWindowFlags_NoResize |
					ImGuiWindowFlags_NoMove |
					ImGuiWindowFlags_NoCollapse |
					ImGuiWindowFlags_NoFocusOnAppearing |
					ImGuiWindowFlags_NoInputs);
			//		if (ECS::get().get<GUI>().enabled)
			//			ECS::get().get<App>().app->setWindowGrab(true);
			ImGui::PushFont(bigFont);
			ImGui::TextWrapped(
				"%s",
				"This game does not autosave. Please use save function to keep your state");
			ImGui::PopFont();
			ImGui::End();
            ImGui::PopStyleColor();
        } else if (ECS::get<GUI>().narrationHandlers.size() > 0) {
            ECS::get_mut<GUI>().grab = false;
            ECS::get_mut<GUI>().grabChanged = true;
            ECS::get_mut<GUI>().enabled = true;
            ECS::get_mut<GUI>().narrationBox = true;
            ImVec2 size = ImGui::GetMainViewport()->Size;
            ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.75f),
                        ImGuiCond_Always);
            ImGui::SetNextWindowSize(ImVec2(size.x, size.y * 0.25f),
                         ImGuiCond_Always);
            ImGui::Begin("Narration...", NULL,
                     ImGuiWindowFlags_NoTitleBar);
            ImGui::PushFont(midFont);
            ImVec2 p = ImGui::GetCursorScreenPos();
            GUI::NarrationHandler *narration =
                ECS::get<GUI>().narrationHandlers.front();
            if (!narration->is_active())
                narration->_event("narration_activate");
            ImGui::TextWrapped(
                "%s", narration->getNarrationText().c_str());
            if (narration->getChoices().size() == 0) {
                ImGui::SetCursorScreenPos(p);
                if (ImGui::InvisibleButton(
                        "Background",
                        ImGui::GetWindowSize()))
                    narration->progress();
            } else {
                int i;
                for (i = 0; i < narration->getChoices().size();
                     i++) {
                    if (ImGui::Button(
                            narration->getChoices()[i]
                                .c_str())) {
                        narration->setNarrationAnswer(
                            i + 1);
                        std::cout << "answer: " << i + 1
                              << std::endl;
                    }
                }
            }
            if (narration->is_complete()) {
                ECS::get_mut<GUI>().enabled = false;
                ECS::get_mut<GUI>().narrationBox = false;
                ECS::get_mut<GUI>().grab = true;
                ECS::get_mut<GUI>().grabChanged = true;
                ECS::get_mut<GUI>().removeNarrationHandler(
                    narration);
                delete narration;
            }
            ImGui::Spacing();
            ImGui::PopFont();
            ImGui::End();
            ECS::modified<GUI>();
        } else if (ECS::get().get<GUI>().narrationBox) {
            ImVec2 size = ImGui::GetMainViewport()->Size;
            ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.75f),
                        ImGuiCond_Always);
            ImGui::SetNextWindowSize(ImVec2(size.x, size.y * 0.25f),
                         ImGuiCond_Always);
            ImGui::Begin("Narration...", NULL,
                     ImGuiWindowFlags_NoTitleBar);
            ImGui::PushFont(midFont);
            ImVec2 p = ImGui::GetCursorScreenPos();
            ImGui::TextWrapped(
                "%s",
                ECS::get().get<GUI>().narrationText.c_str());
            if (ECS::get().get<GUI>().choices.size() == 0) {
                ImGui::SetCursorScreenPos(p);
                if (ImGui::InvisibleButton(
                        "Background",
                        ImGui::GetWindowSize()))
                    ECS::get<LuaBase>().mLua->call_handler(
                        "narration_progress");
            } else {
                int i;
                for (i = 0;
                     i < ECS::get().get<GUI>().choices.size();
                     i++) {
                    if (ImGui::Button(ECS::get()
                                  .get<GUI>()
                                  .choices[i]
                                  .c_str())) {
                        ECS::get()
                            .get_mut<GUI>()
                            .narration_answer =
                            i + 1;
                        std::cout << "answer: " << i + 1
                              << std::endl;
                        ECS::modified<GUI>();
                        ECS::get<LuaBase>().mLua->call_handler(
                            "narration_answered");
                    }
                }
            }
            ImGui::Spacing();
            ImGui::PopFont();
            ImGui::End();
        } else if (ECS::get().get<GUI>().enabled) {
            if (ECS::get().get<GUI>().mainMenu) {
                ImGuiViewport *viewport =
                    ImGui::GetMainViewport();
                ImGui::SetNextWindowPos(viewport->WorkPos,
                            ImGuiCond_Always);
                ImGui::SetNextWindowSize(viewport->WorkSize,
                             ImGuiCond_Always);
                ImGui::PushStyleVar(
                    ImGuiStyleVar_WindowRounding, 0.0f);
                ImGui::PushStyleVar(
                    ImGuiStyleVar_WindowBorderSize, 0.0f);

#if 0
				ImGui::SetNextWindowPos(ImVec2(0, 0),
							ImGuiCond_Always);
                ImGui::SetNextWindowSize(ImVec2(size.x + 4,
                                size.y + 1),
							 ImGuiCond_Always);
#endif
                ImVec4 solidColor =
                    ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
                ImGui::PushStyleColor(ImGuiCol_WindowBg,
                              solidColor);
                ImGui::Begin(
					"MainMenu", nullptr,
					ImGuiWindowFlags_NoTitleBar |
						ImGuiWindowFlags_NoDecoration |

						ImGuiWindowFlags_NoResize |
						ImGuiWindowFlags_NoMove |
						ImGuiWindowFlags_NoCollapse |
                        ImGuiWindowFlags_NoFocusOnAppearing |
                        ImGuiWindowFlags_NoSavedSettings |
                        ImGuiWindowFlags_NoBringToFrontOnFocus |
						0);
                struct buttons {
                    std::string label;
                    std::function<void(bool)> callback;
                };
                bool new_game = false, cont = false,
                     load_game = false, opts = false,
                     quit = false;
                struct buttons buttons_data[] = {
                    { "New Game",
                      [&](bool pressed) {
                          new_game = true;
                      } },
                    { "Continue",
                      [&](bool pressed) { cont = true; } },
                    { "Load Game",
                      [&](bool pressed) {
                          load_game = true;
                      } },
                    { "Options",
                      [&](bool pressed) { opts = true; } },
                    { "Quit###quit",
                      [&](bool pressed) { quit = true; } },
                };
                ImVec2 size = ImGui::GetWindowSize();
                float window_width = size.x;
                float window_height = size.y;
                ImGui::PushFont(bigFont);
				ImGui::TextWrapped("%s", "Booo!!!!");
                float extra_pixels = 20.0f;
                float button_width = 0.0f;
                float buttons_height = 0.0f;
                for (const struct buttons &b : buttons_data) {
                    ImVec2 text_size = ImGui::CalcTextSize(
                        b.label.c_str());
                    float text_width = text_size.x;
                    float text_height = text_size.y;
                    float bwidth =
                        text_width +
                        (ImGui::GetStyle()
                             .FramePadding.x *
                         2.0f) +
                        extra_pixels;
                    if (button_width < bwidth)
                        button_width = bwidth;
                    buttons_height +=
                        text_height +
                        (ImGui::GetStyle()
                             .FramePadding.y *
                         2.0f);
                }
                ImGui::SetCursorPosY(
                    (window_height - buttons_height) *
                    0.5f);
                for (const struct buttons &b : buttons_data) {
                    ImGui::SetCursorPosX(
                        (window_width - button_width) *
                        0.5f);
                    if (ImGui::Button(b.label.c_str(),
                              ImVec2(button_width,
                                 0)))
                        b.callback(true);
                }
                bool pressed = false;
				pressed = new_game || cont || load_game ||
					  opts || quit;
				ImGui::PopFont();
				ImGui::Spacing();
				ImGui::End();
                ImGui::PopStyleColor();
                ImGui::PopStyleVar();
                ImGui::PopStyleVar();
                if (quit)
					Ogre::Root::getSingleton()
						.queueEndRendering();
				if (pressed)
					ECS::get().get<GUI>().finish();
				if (new_game) {
                    ECS::get().set<GameState>({ true });
                    ECS::get<LuaBase>().mLua->call_handler(
                        "new_game_selected");
                } else if (load_game) {
                    ECS::get().set<GameState>({ true });
                    ECS::get<LuaBase>().mLua->call_handler(
                        "load_game_selected");
                }
            } else {
				buttons_panel();
				if (enableEditor)
					buildings_editor();
				if (enableMapEditor)
					map_editor();
				ImVec2 size = ImGui::GetMainViewport()->Size;
				float window_width = size.x * 0.2f;
				if (window_width > panel_width)
					window_width = panel_width;
				float window_height = size.y * 0.5f - 20;
				ImGui::SetNextWindowPos(
					ImVec2(size.x - window_width,
					       size.y * 0.5f + 20),
					ImGuiCond_Always);
				ImGui::SetNextWindowSize(ImVec2(window_width,
								window_height),
							 ImGuiCond_Always);
				ImGui::Begin("Panel...");
				std::deque<Ogre::SceneNode *> tree_input_queue,
					tree_output_queue;
				std::vector<Ogre::SceneNode *> tree_list;
				tree_input_queue.push_back(
					ECS::get()
						.get<EngineData>()
						.mScnMgr->getRootSceneNode());
				tree_input_queue.push_back(nullptr);
				std::set<Ogre::SceneNode *> visited;
				while (true) {
					int new_nodes_count = 0;
					while (!tree_input_queue.empty()) {
						int child;
						Ogre::SceneNode *item =
							tree_input_queue.front();
						tree_input_queue.pop_front();
						if (item &&
						    visited.find(item) ==
							    visited.end()) { // new node
							new_nodes_count++;
							tree_output_queue
								.push_back(
									item);
							visited.insert(item);
							const Ogre::Node::ChildNodeMap
								&children =
									item->getChildren();
							for (child = 0;
							     child <
							     children.size();
							     child++) {
								tree_output_queue
									.push_back(static_cast<
										   Ogre::SceneNode
											   *>(
										children[child]));
								tree_output_queue
									.push_back(
										nullptr);
							}
						} else
							tree_output_queue
								.push_back(
									item);
					}
					if (new_nodes_count == 0)
						break;
					tree_input_queue = tree_output_queue;
					tree_output_queue.clear();
				}
				tree_list.insert(tree_list.begin(),
						 tree_output_queue.begin(),
						 tree_output_queue.end());
				int count = 0;
				int depth = 0;
				std::vector<int> check_depth;
				int max_depth = 0;
				check_depth.push_back(0);
				for (count = 0; count < tree_list.size();
				     count++) {
					int t;

					Ogre::SceneNode *node =
						tree_list[count];
					if (node && max_depth >= depth) {
						Ogre::String name =
							node->getName();
						if (name.length() == 0) {
							name = "Node #" +
							       Ogre::StringConverter::
								       toString(
									       count);
						}
						if (ImGui::TreeNode(
							    name.c_str())) {
							check_depth.push_back(
								max_depth);
							max_depth++;
							ImGui::Text(
								"%s",
								(name +
								 "##caption")
									.c_str());
							position_editor(node);
							ImGui::Separator();
							orientation_editor(
								node);
							ImGui::Separator();
							ImGui::Text(
								"Attachments");
							attachments_editor(
								node);
						}
					} else if (!node &&
						   max_depth >= depth) {
						max_depth = check_depth.back();
						check_depth.pop_back();
						ImGui::TreePop();
					}
					if (tree_list[count])
						depth++;
					else
						depth--;
				}
				ImGui::Spacing();
				ImGui::End();
			}
        } else {
            ECS::ActionNodeList &list =
                ECS::get_mut<ECS::ActionNodeList>();
            if (list.dynamicNodes.size() > 0 &&
                ECS::get<GUI>().enableActions) {
                int j;
                Ogre::Vector3 queryPos;
                std::vector<size_t> points =
                    list.getUIData().points;
                std::vector<float> distances =
                    list.getUIData().distances;

                Ogre::SceneNode *cameraNode =
                    ECS::get<Camera>().mCameraNode;
                Ogre::Vector3 cameraPos =
                    cameraNode->_getDerivedPosition();
                float minDistance = 25.0f;
                int i;
                list.setUISelected(-1);
                for (i = 0; i < points.size(); i++) {
                    size_t p = points[i];
                    float distance = distances[i];
                    float radius = list.dynamicNodes[p]
                                   .props["radius"]
                                   .get<float>();
                    float height = list.dynamicNodes[p]
                                   .props["height"]
                                   .get<float>();
                    float actDistance = radius * radius +
                                height * height;
                    float textDistance =
                        actDistance + 2.0f * 2.0f;
                    Ogre::Vector2 screenPos =
                        projectToScreen(
                            list.dynamicNodes[p]
                                .position);
                    if (screenPos.x < 0)
                        continue;
                    // FIXME: move this to system to filter points there
                    Ogre::Vector3 hitPosition;
                    JPH::BodyID hitBody;
                    bool hit =
                        JoltPhysicsWrapper::getSingleton()
                            .raycastQuery(
                                list.dynamicNodes[p]
                                    .position,
                                cameraPos,
                                hitPosition,
                                hitBody);
                    if (hit)
                        continue;

                    if (list.getUIData().selected == -1) {
                        if (distance < actDistance)
                            list.setUISelected(p);
                    }
                    ImDrawList *drawList =
                        ImGui::GetBackgroundDrawList();
                    ImVec2 center = ImVec2(screenPos.x,
                                   screenPos.y);
                    float circleRadius = 8.0f;
                    ImColor circleColor(
                        ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
                    if (p == list.getUIData().selected) {
                        circleRadius = 16.0f;
                        circleColor = ImColor(
                            ImVec4(0, 0, 1, 1));
                    }
                    drawList->AddCircleFilled(center,
                                  circleRadius,
                                  circleColor);
                    drawList->AddCircle(
                        center, circleRadius,
                        IM_COL32(64, 64, 255, 255));
                    ImVec2 textSize = ImGui::CalcTextSize(
                        list.dynamicNodes[p]
                            .action_text.c_str());
                    ImVec2 textPos = ImVec2(
                        center.x - (textSize.x * 0.5f),
                        center.y + circleRadius + 4.0f);
                    if (distance < textDistance) {
                        drawList->AddText(
                            ImVec2(textPos.x + 1,
                                   textPos.y + 1),
                            IM_COL32(0, 0, 0, 200),
                            list.dynamicNodes[p]
                                .action_text
                                .c_str());
                        drawList->AddText(
                            ImVec2(textPos.x,
                                   textPos.y),
                            IM_COL32(255, 32, 64,
                                 255),
                            list.dynamicNodes[p]
                                .action_text
                                .c_str());
                    }
                }
            }
        }
	}
};

GUIModule::GUIModule(flecs::world &ecs)
{
	ecs.module<GUIModule>();
	ecs.import <AppModule>();
    ecs.import <QuestModule>();
	ecs.component<GUI>()
		.on_add([](GUI &gui) {
			gui.enabled = false;
			gui.grab = false;
			gui.grabChanged = false;
            gui.enableActions = true;
        })
		.add(flecs::Singleton);
	ecs.component<GUIData>()
		.on_add([](GUIData &priv) {
			priv.glb_names.clear();
			priv.mGUIListener = nullptr;
			priv.mGuiOverlay = nullptr;
		})
		.add(flecs::Singleton);
}

void GUIModule::configure()
{
    ZoneScoped;
    ECS::get().set<GUIData>({ nullptr, {}, nullptr });
    const RenderWindow &window = ECS::get<RenderWindow>();
    GUIData &gui = ECS::get_mut<GUIData>();
    const App &app = ECS::get<App>();
    if (gui.mGuiOverlay)
        return;
    float vpScale = window.dpi / 96;
    if (vpScale < 1.0f)
        vpScale = 1.0f;
    Ogre::OverlayManager::getSingleton().setPixelRatio(vpScale);
    std::cout << "GUI configure\n";
    OgreAssert(app.mGuiOverlay, "No ImGUI overlay");
    gui.mGuiOverlay = app.mGuiOverlay;
    gui.mGUIListener = new GUIListener();
    gui.mGuiOverlay->setZOrder(300);
    gui.mGuiOverlay->show();
    gui.mGUIListener->panel_width = 300.0f;
    gui.mGUIListener->enableEditor = false;
    window.window->addListener(gui.mGUIListener);
    int i;

    const std::vector<Ogre::String> &groups =
        Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
    for (i = 0; i < groups.size(); i++) {
        std::vector<Ogre::String> names =
            *Ogre::ResourceGroupManager::getSingleton()
                 .findResourceNames(groups[i], "*.glb");
        gui.glb_names.insert(gui.glb_names.end(), names.begin(),
                     names.end());
    }
    ECS::modified<GUIData>();
    std::cout << "GUI configure finished\n";
}
}
