#ifndef EDITSCENE_GOAP_PLANNER_SYSTEM_HPP
#define EDITSCENE_GOAP_PLANNER_SYSTEM_HPP
#pragma once

#include <flecs.h>
#include <Ogre.h>
#include <vector>
#include <string>
#include <queue>
#include <unordered_set>

// Forward declarations
class EditorApp;
class ActionDatabase;
struct GoapPlannerComponent;
struct GoapAction;
struct GoapGoal;
struct GoapBlackboard;

/**
 * GOAP Planner system.
 *
 * Runs A* planning for entities with GoapPlannerComponent + GoapBlackboard.
 * When planDirty is set:
 *   1. Selects the highest-priority valid goal from the planner's goal list
 *   2. Resolves action names against ActionDatabase
 *   3. Runs forward A* search to find action sequences reaching the goal
 *   4. Stores up to maxPlans plans in the planner's planQueue
 *   5. Sets status to PlansAvailable or NoPlanFound
 */
class GoapPlannerSystem {
public:
	GoapPlannerSystem(flecs::world &world);
	~GoapPlannerSystem();

	void update(float deltaTime);

	/**
	 * Set the EditorApp for game mode detection.
	 * Planning only runs when playing (game mode) or always in editor.
	 */
	void setEditorApp(EditorApp *app)
	{
		m_editorApp = app;
	}

private:
	void planForEntity(flecs::entity e, GoapPlannerComponent &planner,
			   const GoapBlackboard &blackboard);

	std::vector<const GoapAction *>
	resolveActions(const GoapPlannerComponent &planner,
		       const ActionDatabase *db);

	const GoapGoal *selectGoal(const GoapPlannerComponent &planner,
				   const ActionDatabase *db,
				   const GoapBlackboard &blackboard);

	// Hash a blackboard state for closed-set deduplication
	static size_t hashState(const GoapBlackboard &bb);
	static bool statesEqual(const GoapBlackboard &a,
				const GoapBlackboard &b);

	flecs::world &m_world;
	EditorApp *m_editorApp = nullptr;
};

#endif // EDITSCENE_GOAP_PLANNER_SYSTEM_HPP
