#include "StartupMenuSystem.hpp"
#include "../EditorApp.hpp"
#include "../components/StartupMenu.hpp"
#include "EventBus.hpp"
#include "SaveLoadDialog.hpp"
#include <imgui.h>
#include <OgreFontManager.h>
#include <OgreImGuiOverlay.h>
#include <OgreLogManager.h>
#include <OgreOverlayManager.h>

StartupMenuSystem::StartupMenuSystem(flecs::world &world,
				     Ogre::SceneManager *sceneMgr,
				     EditorApp *editorApp)
	: m_world(world)
	, m_sceneMgr(sceneMgr)
	, m_editorApp(editorApp)
{
}

StartupMenuSystem::~StartupMenuSystem() = default;

void StartupMenuSystem::ensureFontLoaded(const Ogre::String &fontName,
					 float fontSize)
{
	if (m_fontLoaded && m_currentFontName == fontName &&
	    m_currentFontSize == fontSize)
		return;

	Ogre::ImGuiOverlay *overlay = m_editorApp->getImGuiOverlay();
	if (!overlay)
		return;

	// Try to load via Ogre font manager
	Ogre::FontPtr font;
	try {
		if (Ogre::FontManager::getSingleton().resourceExists(
			    "StartupMenuFont", "General")) {
			Ogre::FontManager::getSingleton().remove(
				"StartupMenuFont", "General");
		}
		font = Ogre::FontManager::getSingleton().create(
			"StartupMenuFont", "General");
		font->setType(Ogre::FontType::FT_TRUETYPE);
		font->setSource(fontName);
		font->setTrueTypeSize(fontSize);
		font->setTrueTypeResolution(75);
		font->addCodePointRange(Ogre::Font::CodePointRange(32, 255));
		font->load();
	} catch (...) {
		Ogre::LogManager::getSingleton().logMessage(
			"StartupMenuSystem: Failed to load font " + fontName);
		m_menuFont = nullptr;
		m_fontLoaded = false;
		return;
	}

	m_menuFont = overlay->addFont("StartupMenuFont", "General");
	m_currentFontName = fontName;
	m_currentFontSize = fontSize;
	m_fontLoaded = true;
}

void StartupMenuSystem::prepareFont()
{
	// Must be called BEFORE Ogre::ImGuiOverlay::show() so that the font
	// is added to the atlas before OGRE builds it in createFontTexture().
	if (!m_editorApp)
		return;

	// Find an entity with StartupMenuComponent
	flecs::entity menuEntity = flecs::entity::null();
	m_world.query<StartupMenuComponent>().each(
		[&](flecs::entity e, StartupMenuComponent &) {
			if (!menuEntity.is_alive())
				menuEntity = e;
		});

	if (menuEntity.is_alive()) {
		auto &sm = menuEntity.get_mut<StartupMenuComponent>();
		Ogre::LogManager::getSingleton().logMessage(
			"StartupMenuSystem: Found menu entity, font=" +
			sm.fontName + ", scene=" + sm.newGameScene);
		ensureFontLoaded(sm.fontName, sm.fontSize);
	} else {
		Ogre::LogManager::getSingleton().logMessage(
			"StartupMenuSystem: No StartupMenuComponent entity found");
	}
}

void StartupMenuSystem::update(float deltaTime)
{
	(void)deltaTime;

	if (!m_editorApp ||
	    m_editorApp->getGamePlayState() != EditorApp::GamePlayState::Menu)
		return;

	// Find an entity with StartupMenuComponent
	flecs::entity menuEntity = flecs::entity::null();
	m_world.query<StartupMenuComponent>().each(
		[&](flecs::entity e, StartupMenuComponent &) {
			if (!menuEntity.is_alive())
				menuEntity = e;
		});

	if (!menuEntity.is_alive()) {
		// No startup menu entity configured
		Ogre::LogManager::getSingleton().logMessage(
			"StartupMenuSystem: Rendering missing menu error");
		renderMissingMenuError();
		return;
	}

	auto &sm = menuEntity.get_mut<StartupMenuComponent>();
	Ogre::LogManager::getSingleton().logMessage(
		"StartupMenuSystem: Rendering menu, scene=" + sm.newGameScene);
	renderMenu(sm);
}

void StartupMenuSystem::renderMenu(StartupMenuComponent &sm)
{
	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(
		"StartupMenu", nullptr,
		ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDecoration |
			ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
			ImGuiWindowFlags_NoCollapse |
			ImGuiWindowFlags_NoFocusOnAppearing);

	if (m_menuFont)
		ImGui::PushFont(m_menuFont);

	struct ButtonData {
		const char *label;
		std::function<void()> action;
	};

	std::vector<ButtonData> buttons;
	buttons.push_back({ "NEW GAME", [&]() {
				   // Send "new_game" event before starting the game
				   EventBus::getInstance().send("new_game");
				   m_editorApp->startNewGame(sm.newGameScene);
			   } });

	if (sm.showLoadGame)
		buttons.push_back(
			{ "LOAD GAME", [&]() {
				 SaveLoadDialog::show(m_editorApp,
						      SaveLoadDialog::Mode::Load);
			 } });

	if (sm.showOptions)
		buttons.push_back(
			{ "OPTIONS", [&]() {
				 Ogre::LogManager::getSingleton().logMessage(
					 "Options not implemented");
			 } });

	if (sm.showQuit)
		buttons.push_back(
			{ "QUIT", [&]() {
				 Ogre::Root::getSingleton().queueEndRendering();
			 } });

	// Calculate button dimensions
	float buttonWidth = 0.0f;
	float buttonsHeight = 0.0f;
	float extraPixels = 20.0f;
	for (const auto &b : buttons) {
		ImVec2 textSize = ImGui::CalcTextSize(b.label);
		float bwidth = textSize.x +
			       (ImGui::GetStyle().FramePadding.x * 2.0f) +
			       extraPixels;
		float bheight =
			textSize.y + (ImGui::GetStyle().FramePadding.y * 2.0f);
		if (buttonWidth < bwidth)
			buttonWidth = bwidth;
		buttonsHeight += bheight + ImGui::GetStyle().ItemSpacing.y;
	}
	if (!buttons.empty())
		buttonsHeight -= ImGui::GetStyle().ItemSpacing.y;

	ImGui::SetCursorPosY((size.y - buttonsHeight) * 0.5f);
	for (const auto &b : buttons) {
		ImGui::SetCursorPosX((size.x - buttonWidth) * 0.5f);
		if (ImGui::Button(b.label, ImVec2(buttonWidth, 0)))
			b.action();
	}

	if (m_menuFont)
		ImGui::PopFont();

	SaveLoadDialog::render(m_editorApp);

	ImGui::End();
	ImGui::PopStyleColor();
}

void StartupMenuSystem::renderMissingMenuError()
{
	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(
		"StartupMenuError", nullptr,
		ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDecoration |
			ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
			ImGuiWindowFlags_NoCollapse |
			ImGuiWindowFlags_NoFocusOnAppearing |
			ImGuiWindowFlags_NoInputs);

	const char *msg = "Error: No StartupMenuComponent entity found.\n"
			  "Make sure startup_menu.json is loaded and contains\n"
			  "an entity with a StartupMenuComponent.";
	ImVec2 textSize = ImGui::CalcTextSize(msg);
	ImGui::SetCursorPosX((size.x - textSize.x) * 0.5f);
	ImGui::SetCursorPosY((size.y - textSize.y) * 0.5f);
	ImGui::TextUnformatted(msg);

	ImGui::End();
	ImGui::PopStyleColor();
}
