#ifndef EDITSCENE_EDITORAPP_HPP
#define EDITSCENE_EDITORAPP_HPP
#pragma once
#include <Ogre.h>
#include <OgreApplicationContext.h>
#include <OgreInput.h>
#include <OgreOverlaySystem.h>
#include <OgreImGuiOverlay.h>
#include <OgreRenderTargetListener.h>
#include <flecs.h>
#include <memory>
#include "lua/LuaState.hpp"

// Forward declarations
class EditorUISystem;
class EditorCamera;
class EditorPhysicsSystem;
class EditorLightSystem;
class EditorCameraSystem;
class EditorLodSystem;
class StaticGeometrySystem;
class ProceduralTextureSystem;
class ProceduralMaterialSystem;
class ProceduralMeshSystem;
class CharacterSlotSystem;
class CharacterSpawnerSystem;
class AnimationTreeSystem;
class HairPhysicsSystem;
class BehaviorTreeSystem;
class NavMeshSystem;
class CharacterSystem;
class CellGridSystem;
class RoomLayoutSystem;
class StartupMenuSystem;
class PauseMenuSystem;
class DialogueSystem;
class PlayerControllerSystem;
class BuoyancySystem;
class EditorSunSystem;
class EditorSkyboxSystem;
class EditorWaterPlaneSystem;
class NormalDebugSystem;
class SmartObjectSystem;
class GoapRunnerSystem;
class PathFollowingSystem;
class GoapPlannerSystem;
class ActuatorSystem;
class EventHandlerSystem;
class ItemSystem;
class CharacterClassSystem;
class PregnancySystem;
class EditorApp;

/**
 * Shared input state for game mode
 */
struct GameInputState {
	bool w = false;
	bool a = false;
	bool s = false;
	bool d = false;
	bool shift = false;
	bool e = false;
	bool f = false;
	bool i = false;
	bool ePressed = false;
	bool fPressed = false;
	bool iPressed = false;
	float mouseDeltaX = 0.0f;
	float mouseDeltaY = 0.0f;
	bool mouseMoved = false;

	void resetPerFrame()
	{
		mouseMoved = false;
		mouseDeltaX = 0.0f;
		mouseDeltaY = 0.0f;
		ePressed = false;
		fPressed = false;
		iPressed = false;
	}

	void clearMovementInput()
	{
		w = false;
		a = false;
		s = false;
		d = false;
		shift = false;
	}
};

/**
 * RenderTargetListener for ImGui frame management
 * Handles NewFrame() in preViewportUpdate and EndFrame() in postViewportUpdate
 */
class ImGuiRenderListener : public Ogre::RenderTargetListener {
public:
	ImGuiRenderListener(Ogre::ImGuiOverlay *imguiOverlay,
			    EditorUISystem *uiSystem,
			    Ogre::RenderWindow *renderWindow,
			    EditorApp *editorApp);

	void
	preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override;
	void
	postViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override;

private:
	Ogre::ImGuiOverlay *m_imguiOverlay;
	EditorUISystem *m_uiSystem;
	Ogre::RenderWindow *m_renderWindow;
	EditorApp *m_editorApp;

	// Timer for delta time calculation
	Ogre::Timer m_timer;
	unsigned long m_lastTime = 0;
	float m_deltaTime = 0.0f;

	// Frame stats (updated in postViewportUpdate)
	int m_lastBatchCount = 0;
};

/**
 * Main application class for the scene editor / game
 */
class EditorApp : public OgreBites::ApplicationContext,
		  public OgreBites::InputListener {
public:
	enum class GameMode { Editor, Game };
	enum class GamePlayState { Menu, Playing, Paused };

	EditorApp();
	virtual ~EditorApp();

	// OgreBites::ApplicationContext overrides
	void setup() override;
	bool frameRenderingQueued(const Ogre::FrameEvent &evt) override;
	void locateResources() override;

	// OgreBites::InputListener overrides
	bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override;
	bool mousePressed(const OgreBites::MouseButtonEvent &evt) override;
	bool mouseReleased(const OgreBites::MouseButtonEvent &evt) override;
	bool keyPressed(const OgreBites::KeyboardEvent &evt) override;
	bool keyReleased(const OgreBites::KeyboardEvent &evt) override;

	// Scene setup
	void setupLights();
	void createGrid();
	void createAxes();

	// ECS setup
	void setupECS();
	void createDefaultEntities();

	// Game mode management
	void setGameMode(GameMode mode);
	GameMode getGameMode() const
	{
		return m_gameMode;
	}

	// Debug buoyancy
	void setDebugBuoyancy(bool enabled);
	bool getDebugBuoyancy() const
	{
		return m_debugBuoyancy;
	}
	GamePlayState getGamePlayState() const
	{
		return m_gamePlayState;
	}
	void setGamePlayState(GamePlayState state);
	void startNewGame(const Ogre::String &scenePath);
	void clearScene();

	// Save / Load
	void saveGame(const std::string &slotPath, const std::string &slotName);
	void loadGame(const std::string &slotPath);

	// Input access
	GameInputState &getGameInputState()
	{
		return m_gameInput;
	}

	// Getters
	flecs::entity getSelectedEntity() const;

	/**
	 * Return the live player character entity that is currently controlled by
	 * the "player" controller. If the controller targets a character spawner,
	 * this returns the spawned character instance, forcing a spawn if necessary.
	 * Returns null if no player controller or target exists.
	 */
	flecs::entity getPlayerCharacterEntity();

	Ogre::SceneManager *getSceneManager() const
	{
		return m_sceneMgr;
	}
	flecs::world *getWorld()
	{
		return &m_world;
	}
	EditorCamera *getEditorCamera() const
	{
		return m_camera.get();
	}
	AnimationTreeSystem *getAnimationTreeSystem() const
	{
		return m_animationTreeSystem.get();
	}
	CharacterSlotSystem *getCharacterSlotSystem() const
	{
		return m_characterSlotSystem.get();
	}
	CharacterSpawnerSystem *getCharacterSpawnerSystem() const
	{
		return m_characterSpawnerSystem.get();
	}
	StartupMenuSystem *getStartupMenuSystem() const
	{
		return m_startupMenuSystem.get();
	}
	PauseMenuSystem *getPauseMenuSystem() const;
	DialogueSystem *getDialogueSystem() const;
	ActuatorSystem *getActuatorSystem() const
	{
		return m_actuatorSystem.get();
	}
	EventHandlerSystem *getEventHandlerSystem() const
	{
		return m_eventHandlerSystem.get();
	}
	CharacterClassSystem *getCharacterClassSystem() const
	{
		return m_characterClassSystem.get();
	}
	PregnancySystem *getPregnancySystem() const
	{
		return m_pregnancySystem.get();
	}
	Ogre::ImGuiOverlay *getImGuiOverlay() const
	{
		return m_imguiOverlay;
	}

private:
	// Ogre objects
	Ogre::SceneManager *m_sceneMgr;
	Ogre::OverlaySystem *m_overlaySystem;
	Ogre::ImGuiOverlay *m_imguiOverlay;

	// ECS
	flecs::world m_world;
	std::vector<flecs::entity> m_defaultEntities;

	// Editor systems
	std::unique_ptr<EditorUISystem> m_uiSystem;
	std::unique_ptr<EditorCamera> m_camera;
	std::unique_ptr<ImGuiRenderListener> m_imguiListener;
	std::unique_ptr<EditorPhysicsSystem> m_physicsSystem;
	std::unique_ptr<BuoyancySystem> m_buoyancySystem;
	std::unique_ptr<EditorSunSystem> m_sunSystem;
	std::unique_ptr<EditorSkyboxSystem> m_skyboxSystem;
	std::unique_ptr<EditorWaterPlaneSystem> m_waterPlaneSystem;
	std::unique_ptr<EditorLightSystem> m_lightSystem;
	std::unique_ptr<EditorCameraSystem> m_cameraSystem;
	std::unique_ptr<EditorLodSystem> m_lodSystem;
	std::unique_ptr<StaticGeometrySystem> m_staticGeometrySystem;
	std::unique_ptr<ProceduralTextureSystem> m_proceduralTextureSystem;
	std::unique_ptr<ProceduralMaterialSystem> m_proceduralMaterialSystem;
	std::unique_ptr<ProceduralMeshSystem> m_proceduralMeshSystem;
	std::unique_ptr<CharacterSlotSystem> m_characterSlotSystem;
	std::unique_ptr<CharacterSpawnerSystem> m_characterSpawnerSystem;
	std::unique_ptr<AnimationTreeSystem> m_animationTreeSystem;
	std::unique_ptr<HairPhysicsSystem> m_hairPhysicsSystem;
	std::unique_ptr<BehaviorTreeSystem> m_behaviorTreeSystem;
	std::unique_ptr<NavMeshSystem> m_navMeshSystem;
	std::unique_ptr<CharacterSystem> m_characterSystem;
	std::unique_ptr<CellGridSystem> m_cellGridSystem;
	std::unique_ptr<NormalDebugSystem> m_normalDebugSystem;
	std::unique_ptr<RoomLayoutSystem> m_roomLayoutSystem;
	std::unique_ptr<SmartObjectSystem> m_smartObjectSystem;
	std::unique_ptr<GoapRunnerSystem> m_goapRunnerSystem;
	std::unique_ptr<PathFollowingSystem> m_pathFollowingSystem;
	std::unique_ptr<GoapPlannerSystem> m_goapPlannerSystem;
	std::unique_ptr<ActuatorSystem> m_actuatorSystem;
	std::unique_ptr<EventHandlerSystem> m_eventHandlerSystem;
	std::unique_ptr<ItemSystem> m_itemSystem;
	std::unique_ptr<CharacterClassSystem> m_characterClassSystem;
	std::unique_ptr<PregnancySystem> m_pregnancySystem;

	// Game systems
	std::unique_ptr<StartupMenuSystem> m_startupMenuSystem;
	std::unique_ptr<PlayerControllerSystem> m_playerControllerSystem;

	// State
	uint16_t m_currentModifiers;
	GameMode m_gameMode = GameMode::Editor;
	GamePlayState m_gamePlayState = GamePlayState::Menu;
	GameInputState m_gameInput;
	bool m_setupComplete = false;
	bool m_debugBuoyancy = false;
	float m_playTime = 0.0f;
	std::string m_currentBaseScene;

	// Lua scripting
	editScene::LuaState m_lua;

	// Editor visualization nodes
	Ogre::SceneNode *m_gridNode = nullptr;
	Ogre::SceneNode *m_axisNode = nullptr;
};

#endif // EDITSCENE_EDITORAPP_HPP
