#ifndef EDITSCENE_PLAYERCONTROLLERSYSTEM_HPP
#define EDITSCENE_PLAYERCONTROLLERSYSTEM_HPP
#pragma once

#include <flecs.h>
#include <Ogre.h>
#include <memory>

#include "../components/PlayerController.hpp"

class EditorApp;
class AnimationTreeSystem;
class CharacterSlotSystem;
class CharacterSpawnerSystem;

/**
 * System that handles player input, camera control (FPS/TPS),
 * character locomotion, and animation state setting in game mode.
 * Only active when EditorApp is in GameMode::Game and GamePlayState::Playing.
 */
class PlayerControllerSystem {
public:
	PlayerControllerSystem(flecs::world &world,
			       Ogre::SceneManager *sceneMgr,
			       EditorApp *editorApp);
	~PlayerControllerSystem();

	void update(float deltaTime);

	/**
	 * Return the live target entity for a controller. If the controller has
	 * already been initialized this frame, returns its cached target. Otherwise
	 * falls back to resolving the controller's targetCharacterName, spawning the
	 * character through a spawner if necessary.
	 */
	flecs::entity getCurrentTarget(flecs::entity controllerEntity);

	/**
	 * Resolve a target name to a live entity. If the named entity is a character
	 * spawner and forceSpawn is true, the spawner is locked and spawned and the
	 * spawned character entity is returned. Direct characters are returned as-is.
	 */
	flecs::entity resolveTargetEntity(const Ogre::String &targetName,
					  bool forceSpawn = false);

private:
	struct ControllerState {
		flecs::entity targetEntity = flecs::entity::null();
		flecs::entity spawnerEntity = flecs::entity::null();
		float yaw = 0.0f;
		float pitch = 0.0f;
		Ogre::SceneNode *pivotNode = nullptr;
		Ogre::SceneNode *goalNode = nullptr;
		bool initialized = false;
		bool faceHidden = false;
	};

	void initController(flecs::entity controllerEntity,
			    PlayerControllerComponent &pc,
			    ControllerState &state);
	void shutdownController(ControllerState &state);
	flecs::entity findTargetEntity(const Ogre::String &name);
	void updateTPSCamera(PlayerControllerComponent &pc,
			     ControllerState &state,
			     const Ogre::Vector3 &charPos, float deltaTime);
	void updateFPSCamera(PlayerControllerComponent &pc,
			     ControllerState &state,
			     const Ogre::Vector3 &charPos);
	void updateLocomotion(PlayerControllerComponent &pc,
			      ControllerState &state, float deltaTime);

	flecs::world &m_world;
	Ogre::SceneManager *m_sceneMgr;
	EditorApp *m_editorApp;
	CharacterSpawnerSystem *m_spawnerSystem;

	std::unordered_map<flecs::entity_t, ControllerState> m_states;

	// Diagnostics for the stuck slow-walk bug
	int m_stuckWalkFrames = 0;
	bool m_stuckWalkLogged = false;
};

#endif // EDITSCENE_PLAYERCONTROLLERSYSTEM_HPP
