#ifndef EDITSCENE_BEHAVIOR_TREE_SYSTEM_HPP
#define EDITSCENE_BEHAVIOR_TREE_SYSTEM_HPP
#pragma once

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

#include "../components/BehaviorTree.hpp"
#include "../components/ActionDebug.hpp"

class AnimationTreeSystem;
class CharacterSystem;

/**
 * Evaluates data-driven BehaviorTreeComponent each frame.
 *
 * Supports:
 *   sequence, selector, invert, task, check,
 *   debugPrint, setAnimationState, isAnimationEnded
 */
class BehaviorTreeSystem {
public:
	BehaviorTreeSystem(flecs::world &world, Ogre::SceneManager *sceneMgr,
			   AnimationTreeSystem *animSystem,
			   CharacterSystem *charSystem = nullptr);
	~BehaviorTreeSystem();

	void update(float deltaTime);

	/** Result of a single behavior tree evaluation tick. */
	enum class Status { success, failure, running };

	/** Per-entity state for tracking behavior tree evaluation.
	 *  Each entity gets its own RunnerState so the same tree
	 *  definition can be shared across multiple characters. */
	struct RunnerState {
		/* Tracks which leaf nodes were active last frame,
		 * keyed by node pointer address string */
		std::unordered_set<std::string> lastActiveLeaves;
		/* Current frame's active leaves */
		std::unordered_set<std::string> currentActiveLeaves;
		bool firstRun = true;

		/* Per-node timers for delay nodes, keyed by node pointer
		 * address string. This allows the same tree to be shared
		 * across multiple characters, each with independent timers. */
		std::unordered_map<std::string, float> nodeTimers;

		/* Result of the root node evaluation from last frame.
		 * Set to Status::running while the tree is active,
		 * Status::success or Status::failure when complete. */
		Status treeResult = Status::running;
	};

	/** Access the per-entity runner state for ActionDebug-driven trees.
	 *  Used by SmartObjectSystem to detect when a behavior tree
	 *  has finished evaluating. */
	const RunnerState &getActionDebugState(flecs::entity_t id) const
	{
		static RunnerState defaultState;
		auto it = m_actionDebugStates.find(id);
		if (it != m_actionDebugStates.end())
			return it->second;
		return defaultState;
	}

	/** Evaluate a behavior tree directly for an entity.
	 *  Used by ActuatorSystem for player action execution.
	 *  Pass reset=true on the first call for a new action.
	 *  Returns running/success/failure. */
	Status evaluatePlayerAction(flecs::entity_t id,
				    const BehaviorTreeNode &root, float deltaTime,
				    bool reset);

private:
	Status evaluateNode(const BehaviorTreeNode &node, flecs::entity e,
			    RunnerState &state, float deltaTime);

	/* Returns true if this leaf just became active this frame */
	bool isNewlyActive(RunnerState &state, const BehaviorTreeNode *node);

	/* Mark leaf as active for this frame */
	void markActive(RunnerState &state, const BehaviorTreeNode *node);

	flecs::world &m_world;
	Ogre::SceneManager *m_sceneMgr;
	AnimationTreeSystem *m_animSystem;
	CharacterSystem *m_charSystem;

	std::unordered_map<flecs::entity_t, RunnerState> m_runnerStates;
	std::unordered_map<flecs::entity_t, RunnerState> m_actionDebugStates;
	std::unordered_map<flecs::entity_t, RunnerState> m_playerActionStates;
};

#endif // EDITSCENE_BEHAVIOR_TREE_SYSTEM_HPP
