#ifndef EDITSCENE_LUA_ENTITY_API_HPP
#define EDITSCENE_LUA_ENTITY_API_HPP
#pragma once

#include <flecs.h>
#include <lua.hpp>
#include <Ogre.h>
#include <unordered_map>

/**
 * @file LuaEntityApi.hpp
 * @brief Lua API for entity creation, destruction, and ID mapping.
 *
 * Provides a bidirectional mapping between Lua integer IDs and
 * Flecs entity handles. Lua scripts reference entities by integer
 * IDs rather than raw Flecs handles for safety and simplicity.
 *
 * Exposed Lua globals:
 *   ecs.create_entity()          -> int (entity ID)
 *   ecs.destroy_entity(id)       -> nil
 *   ecs.entity_exists(id)        -> bool
 *   ecs.get_player_entity()      -> int (entity ID)
 *   ecs.get_entity_by_name(name) -> int (entity ID) or nil
 *   ecs.set_entity_name(id, name)-> nil
 *   ecs.get_entity_name(id)      -> string or nil
 *   ecs.parent(id)               -> int (parent ID) or nil
 *   ecs.children(id)             -> table of child IDs
 */

namespace editScene
{

/**
 * @brief Global bidirectional mapping between Lua integer IDs and Flecs entities.
 *
 * This is a singleton-like global so that all Lua API functions can
 * access it without needing to pass it through every closure.
 */
struct LuaEntityIdMap {
	std::unordered_map<int, flecs::entity> id2entity;
	std::unordered_map<flecs::entity_t, int> entity2id;
	int nextId = 0;

	/** @brief Get the next available integer ID. */
	int getNextId()
	{
		nextId++;
		return nextId;
	}

	/**
	 * @brief Add an entity to the map, returning its integer ID.
	 * If the entity is already mapped, returns the existing ID.
	 */
	int addEntity(flecs::entity e)
	{
		if (entity2id.find(e.id()) != entity2id.end())
			return entity2id[e.id()];
		int id = getNextId();
		id2entity[id] = e;
		entity2id[e.id()] = id;
		return id;
	}

	/**
	 * @brief Get the Flecs entity for an integer ID.
	 * Asserts if the ID is not found or the entity is invalid.
	 */
	flecs::entity getEntity(int id)
	{
		auto it = id2entity.find(id);
		OgreAssert(it != id2entity.end(), "Invalid entity ID");
		OgreAssert(it->second.is_valid(), "Entity is no longer valid");
		return it->second;
	}

	/**
	 * @brief Remove an entity from the map.
	 */
	void removeEntity(flecs::entity e)
	{
		auto it = entity2id.find(e.id());
		if (it != entity2id.end()) {
			id2entity.erase(it->second);
			entity2id.erase(it);
		}
	}

	/**
	 * @brief Check if an integer ID is valid.
	 */
	bool hasId(int id) const
	{
		auto it = id2entity.find(id);
		return it != id2entity.end() && it->second.is_valid();
	}
};

/** @brief Global entity ID map instance. */
extern LuaEntityIdMap g_luaEntityIdMap;

/**
 * @brief Convert a Flecs entity to a Lua integer ID.
 * @return The integer ID, or -1 if the entity is invalid.
 */
int luaEntityToId(flecs::entity e);

/**
 * @brief Convert a Lua integer ID to a Flecs entity.
 * Asserts if the ID is invalid.
 */
flecs::entity luaIdToEntity(int id);

/**
 * @brief Register all entity-related Lua API functions into the global table.
 *
 * Creates the "ecs" global table (or adds to it) with entity management
 * functions. Must be called after LuaState is constructed.
 *
 * @param L The Lua state.
 */
void registerLuaEntityApi(lua_State *L);

} // namespace editScene

#endif // EDITSCENE_LUA_ENTITY_API_HPP
