#ifndef EDITSCENE_EDITORUISYSTEM_HPP
#define EDITSCENE_EDITORUISYSTEM_HPP
#pragma once
#include <flecs.h>
#include <Ogre.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include "../ui/ComponentRegistry.hpp"
#include "../ui/ActionDatabaseSingletonEditor.hpp"
#include "../ui/CharacterClassDatabaseEditor.hpp"
#include "../components/EntityName.hpp"
#include "../gizmo/Gizmo.hpp"
#include "../gizmo/Cursor3D.hpp"
#include "SceneSerializer.hpp"
#include "CharacterRegistry.hpp"

// Forward declarations
class EditorPhysicsSystem;
class BuoyancySystem;
class NormalDebugSystem;
class EditorCamera;

namespace Ogre
{
class RenderWindow;
}

/**
 * Main UI system for the scene editor
 * Handles rendering of:
 * - Left window: Entity hierarchy
 * - Right window: Property editor
 * - 3D Gizmo for transform editing
 */
class EditorUISystem {
public:
	EditorUISystem(flecs::world &world, Ogre::SceneManager *sceneMgr,
		       Ogre::RenderWindow *renderWindow = nullptr);
	~EditorUISystem();

	/**
	 * Update and render all UI windows
	 * Call this once per frame
	 */
	void update(float deltaTime);

	/**
	 * Render FPS and batch count overlay
	 */
	void renderFPSOverlay(float deltaTime);

	/**
	 * Set the currently selected entity
	 */
	void setSelectedEntity(flecs::entity entity);

	/**
	 * Add existing entity to cache (for entities created before UI)
	 */
	void addEntity(flecs::entity entity)
	{
		m_allEntities.push_back(entity);
	}

	/**
	 * Remove an entity from the cached list.
	 *
	 * Used for runtime entities that should not be tracked by the editor UI
	 * (e.g. characters spawned by CharacterSpawnerSystem).
	 */
	void removeEntity(flecs::entity entity)
	{
		auto it = std::find(m_allEntities.begin(), m_allEntities.end(),
				    entity);
		if (it != m_allEntities.end())
			m_allEntities.erase(it);
	}

	/**
	 * Clear entity cache and deselect
	 */
	void clearEntityCache()
	{
		m_allEntities.clear();
		setSelectedEntity(flecs::entity::null());
	}

	/**
	 * Delete entity and all its children, cleaning up OGRE objects
	 */
	void deleteEntity(flecs::entity entity);

	/**
	 * Get the currently selected entity
	 */
	flecs::entity getSelectedEntity() const
	{
		return m_selectedEntity;
	}

	/**
	 * Handle mouse events for gizmo interaction
	 * Returns true if gizmo handled the event
	 */
	bool onMousePressed(const Ogre::Ray &mouseRay);
	bool onMouseMoved(const Ogre::Ray &mouseRay,
			  const Ogre::Vector2 &mouseDelta);
	bool onMouseReleased();

	/**
	 * Get the gizmo for external interaction
	 */
	Gizmo *getGizmo() const
	{
		return m_gizmo.get();
	}

	/**
	 * Get the 3D cursor for external interaction
	 */
	Cursor3D *getCursor3D() const
	{
		return m_cursor3D.get();
	}

	/**
	 * Shutdown UI system - must be called before SceneManager destruction
	 */
	void shutdown();

	/**
	 * Get/set SceneNode parenting mode
	 */
	bool getParentSceneNodes() const
	{
		return m_parentSceneNodes;
	}
	void setParentSceneNodes(bool value)
	{
		m_parentSceneNodes = value;
	}

	/**
	 * Set physics system for debug toggle
	 */
	void setPhysicsSystem(EditorPhysicsSystem *physics)
	{
		m_physicsSystem = physics;
	}

	/**
	 * Set buoyancy system for configuration
	 */
	void setBuoyancySystem(BuoyancySystem *buoyancy)
	{
		m_buoyancySystem = buoyancy;
	}

	/**
	 * Set normal debug system for toggle
	 */
	void setNormalDebugSystem(NormalDebugSystem *normalDebug)
	{
		m_normalDebugSystem = normalDebug;
	}

	/**
	 * Set editor camera for cursor drag operations
	 */
	void setEditorCamera(EditorCamera *camera)
	{
		m_editorCamera = camera;
	}

	/**
	 * Enable/disable editor UI rendering
	 */
	void setEditorUIEnabled(bool enabled)
	{
		m_editorUIEnabled = enabled;
	}

	/**
	 * Set last frame batch count (called from render listener)
	 */
	void setLastBatchCount(int count)
	{
		m_lastBatchCount = count;
	}

	/**
	 * Save scene to file
	 */
	void saveScene(const std::string &filepath);

	/**
	 * Load scene from file
	 */
	void loadScene(const std::string &filepath);

	/**
	 * Show file dialog for save/load
	 */
	void showFileDialog(bool isSave);
	void renderFileDialog();
	void closeFileDialog();

	/**
	 * Prefab operations
	 */
	void showCreatePrefabDialog(flecs::entity entity);
	void renderPrefabBrowser();
	void renderCursorPanel();
	void renderDialogueSettingsWindow();
	void renderInventoryConfigWindow();

	CharacterRegistry &getCharacterRegistry()
	{
		return m_characterRegistry;
	}

private:
	// File menu
	void renderFileMenu();
	// Window rendering functions
	void renderHierarchyWindow();
	void renderPropertyWindow();

	// Entity operations
	void renderEntityNode(flecs::entity entity, int depth);
	void renderEntityContextMenu(flecs::entity entity);
	void createNewEntity();
	void createChildEntity(flecs::entity parent);
	void duplicateEntity(flecs::entity entity);

	// Component operations
	void renderComponentList(flecs::entity entity);
	void renderAddComponentMenu(flecs::entity entity);
	void renderRemoveComponentMenu(flecs::entity entity);

	// Helper functions
	void registerComponentEditors();
	void registerModularComponents();
	flecs::entity findEntityParent(flecs::entity entity);
	std::vector<flecs::entity> getEntityChildren(flecs::entity entity);
	bool isDescendantOf(flecs::entity potentialChild,
			    flecs::entity potentialParent);

	// Core references
	flecs::world m_world;
	Ogre::SceneManager *m_sceneMgr;

	// State
	flecs::entity m_selectedEntity;
	ComponentRegistry m_componentRegistry;
	std::vector<flecs::entity> m_allEntities;
	std::unique_ptr<Gizmo> m_gizmo;
	std::unique_ptr<Cursor3D> m_cursor3D;
	std::unique_ptr<SceneSerializer> m_serializer;

	// Settings
	bool m_parentSceneNodes =
		true; // Whether child entities inherit parent's SceneNode

	// FPS overlay settings
	bool m_showFPSOverlay = true; // Show FPS counter by default

	// FPS tracking
	float m_fpsTimeAccumulator = 0.0f;
	int m_fpsFrameCount = 0;
	float m_currentFPS = 0.0f;
	int m_lastBatchCount = 0;

	// Physics system reference (for debug toggle)
	EditorPhysicsSystem *m_physicsSystem = nullptr;

	// Buoyancy system reference (for configuration)
	BuoyancySystem *m_buoyancySystem = nullptr;

	// Normal debug system reference (for toggle)
	NormalDebugSystem *m_normalDebugSystem = nullptr;

	// Editor UI enabled flag
	bool m_editorUIEnabled = true;

	// Render window reference (for viewport access)
	Ogre::RenderWindow *m_renderWindow = nullptr;

	// File dialog state
	bool m_showFileDialog = false;
	bool m_fileDialogIsSave = false; // true = save, false = load
	std::string m_currentPath;
	std::string m_selectedFile;
	std::vector<std::string> m_directoryContents;
	bool m_refreshDirectory = true;
	char m_filenameBuffer[256] = "scene.json";

	// Prefab dialog state
	bool m_showCreatePrefabDialog = false;
	flecs::entity m_prefabSourceEntity = flecs::entity::null();
	char m_prefabNameBuffer[256] = { 0 };
	bool m_showPrefabBrowser = false;
	std::vector<std::string> m_prefabFiles;
	bool m_refreshPrefabList = true;
	bool m_prefabInstAtRoot = false;
	bool m_prefabUseCursor = true; // Use 3D cursor for prefab placement
	float m_prefabRaycastMargin =
		0.0f; // Vertical margin for raycast placement

	// Prefab delete confirmation
	bool m_showDeletePrefabConfirm = false;
	std::string m_prefabToDelete;

	// 3D Cursor state
	bool m_showCursorPanel = false;
	enum class CursorInteractionMode {
		None,
		Place, // Click to raycast-place on surface
		Translate, // Drag axis to translate cursor
		Rotate // Drag axis to rotate cursor
	};
	CursorInteractionMode m_cursorMode = CursorInteractionMode::None;

	// Camera reference for cursor placement/rotation
	EditorCamera *m_editorCamera = nullptr;

	// Action Database singleton editor state
	bool m_showActionDatabaseSingleton = false;
	ActionDatabaseSingletonEditor m_actionDatabaseSingletonEditor;

	// Dialogue settings editor state
	bool m_showDialogueSettings = false;

	// Inventory config editor state
	bool m_showInventoryConfig = false;

	// Character class database editor state
	bool m_showCharacterClassDatabase = false;
	CharacterClassDatabaseEditor m_characterClassDatabaseEditor;

	// Character registry
	bool m_showCharacterRegistry = false;
	CharacterRegistry m_characterRegistry;

	// Item registry
	bool m_showItemRegistry = false;

	// Queries
	flecs::query<EntityNameComponent> m_nameQuery;

	// Constants
	static constexpr float LEFT_PANEL_WIDTH = 300.0f;
	static constexpr float RIGHT_PANEL_WIDTH = 350.0f;
};

#endif // EDITSCENE_EDITORUISYSTEM_HPP
