#ifndef EDITSCENE_SMART_OBJECT_SYSTEM_HPP
#define EDITSCENE_SMART_OBJECT_SYSTEM_HPP
#pragma once

#include <flecs.h>
#include <Ogre.h>
#include <unordered_map>
#include <vector>

class NavMeshSystem;
class BehaviorTreeSystem;
class AnimationTreeSystem;
class ItemSystem;
class EditorApp;

/**
 * System that manages Smart Object interactions.
 *
 * For each entity with CharacterComponent and a blackboard:
 * 1. Scans for nearby SmartObjectComponent entities
 * 2. If a smart object action is relevant to the character's GOAP state,
 *    pathfinds to the smart object
 * 3. Follows the path until within radius (XZ) and height (Y) threshold
 * 4. Executes the smart object's action behavior tree
 */
class SmartObjectSystem {
public:
	SmartObjectSystem(flecs::world &world, Ogre::SceneManager *sceneMgr,
			  NavMeshSystem *navSystem,
			  BehaviorTreeSystem *btSystem);
	~SmartObjectSystem();

	static SmartObjectSystem *getInstance()
	{
		return s_instance;
	}

	/**
	 * Set the AnimationTreeSystem for animation state machine control.
	 * Must be called after construction.
	 */
	void setAnimationTreeSystem(AnimationTreeSystem *system)
	{
		m_animTreeSystem = system;
	}

	/**
	 * Set the EditorApp for game mode detection.
	 * When in game mode, player-controlled characters are skipped
	 * to avoid animation conflicts with PlayerControllerSystem.
	 * In editor mode, player characters can still be tested via
	 * ActionDebug.
	 */
	void setEditorApp(EditorApp *app)
	{
		m_editorApp = app;
	}

	/**
	 * Set the ItemSystem for behavior tree item/inventory nodes.
	 */
	void setItemSystem(ItemSystem *system)
	{
		m_itemSystem = system;
	}

	/**
	 * Get the ItemSystem for behavior tree item/inventory nodes.
	 */
	ItemSystem *getItemSystem() const
	{
		return m_itemSystem;
	}

	void update(float deltaTime);

	/**
	 * Test-run a smart object action on a character.
	 * Used by ActionDebugEditor.
	 */
	bool testSmartObjectAction(flecs::entity character,
				   flecs::entity smartObject,
				   const Ogre::String &actionName);

	/**
	 * Check if a character's smart object interaction is idle.
	 * Returns true if the character is not currently pathfinding,
	 * moving, or executing a smart object action.
	 */
	bool isIdle(flecs::entity character) const;

private:
	struct SmartObjectTarget {
		flecs::entity smartObject;
		Ogre::String actionName;
		std::vector<Ogre::Vector3> path;
		int pathIndex = 0;
		float pathRecalcTimer = 0.0f;
		bool isExecuting = false;
		float executionTimer = 0.0f;
	};

	enum class State { Idle, Pathfinding, Moving, Executing };

	struct CharacterState {
		State state = State::Idle;
		SmartObjectTarget target;
		float scanTimer = 0.0f;
	};

	bool isInRange(const Ogre::Vector3 &charPos,
		       const Ogre::Vector3 &objPos, float radius, float height);

	Ogre::Vector3 getEntityPosition(flecs::entity e);

	/**
	 * Rotate character to face a target direction (Y plane only).
	 * Uses the scene node's yaw rotation.
	 */
	void rotateTowards(flecs::entity e, const Ogre::Vector3 &direction,
			   float deltaTime);

	/**
	 * Set the locomotion animation state (idle/walk/run) via the
	 * AnimationTreeSystem.
	 */
	void setLocomotionState(flecs::entity e, const Ogre::String &stateName);

	/**
	 * Get the front-facing axis for a character entity.
	 * Checks CharacterSlotsComponent first, defaults to -Z.
	 */
	Ogre::Vector3 getFrontAxis(flecs::entity e) const;

	flecs::world &m_world;
	Ogre::SceneManager *m_sceneMgr;
	NavMeshSystem *m_navSystem;
	BehaviorTreeSystem *m_btSystem;
	AnimationTreeSystem *m_animTreeSystem;
	EditorApp *m_editorApp = nullptr;
	ItemSystem *m_itemSystem = nullptr;

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

	static SmartObjectSystem *s_instance;
};

#endif // EDITSCENE_SMART_OBJECT_SYSTEM_HPP
