#ifndef EDITSCENE_CHARACTERSPAWNERSYSTEM_HPP
#define EDITSCENE_CHARACTERSPAWNERSYSTEM_HPP
#pragma once

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

class EditorCameraSystem;
class EditorUISystem;

/**
 * @brief Distance-based character spawning system.
 *
 * Queries entities with CharacterSpawnerComponent and TransformComponent.
 * Spawns the referenced registry character when the active camera is within
 * spawnDistanceSq, and despawns it when the camera moves beyond
 * despawnDistanceSq. Registry changes that bump the character version also
 * trigger a respawn.
 */
class CharacterSpawnerSystem {
public:
	CharacterSpawnerSystem(flecs::world &world,
			       Ogre::SceneManager *sceneMgr,
			       EditorCameraSystem *cameraSystem,
			       EditorUISystem *uiSystem = nullptr);
	~CharacterSpawnerSystem();

	void initialize();
	void update();

	/**
	 * Manually despawn the character associated with a spawner, if any.
	 */
	void despawn(flecs::entity spawnerEntity);

	/**
	 * Force an immediate spawn for the given spawner, regardless of camera
	 * distance. Does nothing if the spawner is missing or invalid.
	 */
	void spawn(flecs::entity spawnerEntity);

	/**
	 * Lock a spawner so that its spawned character is kept alive even when
	 * the camera moves out of range. Multiple locks are idempotent.
	 */
	void lockSpawner(flecs::entity spawnerEntity);

	/**
	 * Remove a lock previously added with lockSpawner().
	 */
	void unlockSpawner(flecs::entity spawnerEntity);

	/**
	 * Return the character entity currently spawned by a spawner, or null if
	 * none is alive.
	 */
	flecs::entity getSpawnedCharacter(flecs::entity spawnerEntity) const;

	/**
	 * Return the spawner entity that currently owns the given character, or null
	 * if the character is not spawned by any known spawner.
	 */
	flecs::entity getSpawnerForCharacter(flecs::entity characterEntity) const;

	/**
	 * Return true if the spawner is currently locked.
	 */
	bool isSpawnerLocked(flecs::entity spawnerEntity) const;

private:
	void spawnCharacter(flecs::entity spawnerEntity,
			    const struct CharacterSpawnerComponent &spawner);
	void destroySpawnedEntity(flecs::entity character);
	void applySpawnerTransform(flecs::entity spawnerEntity,
				   flecs::entity characterEntity);
	Ogre::Vector3 getCameraPosition() const;

	flecs::world &m_world;
	Ogre::SceneManager *m_sceneMgr;
	EditorCameraSystem *m_cameraSystem;
	EditorUISystem *m_uiSystem;
	flecs::query<struct CharacterSpawnerComponent, struct TransformComponent>
		m_query;
	bool m_initialized = false;

	struct SpawnerTransformSnapshot {
		Ogre::Vector3 position;
		Ogre::Quaternion rotation;
		Ogre::Vector3 scale;
	};

	std::unordered_map<flecs::entity_t, flecs::entity> m_spawnedEntities;
	std::unordered_map<flecs::entity_t, uint64_t> m_spawnedVersions;
	std::unordered_map<flecs::entity_t, SpawnerTransformSnapshot>
		m_lastSpawnerTransforms;
	std::unordered_set<flecs::entity_t> m_lockedSpawners;
};

#endif // EDITSCENE_CHARACTERSPAWNERSYSTEM_HPP
