#ifndef ENTITY_REGISTRY_HPP_
#define ENTITY_REGISTRY_HPP_

#include <unordered_map>
#include <functional>
#include <memory>
#include <string>

#include <Entity/Entity.hpp>

/**
 * @brief Registry of entities; maps entity type IDs to factories.
 */
class EntityRegistry
{
private:
    typedef std::function<std::shared_ptr<Entity>(World&, uint64_t, const uint8_t*, size_t)> Factory;

    std::unordered_map<std::string, Factory> m_factories;

    template<typename TEntity>
    void registerEntity(std::string typeId)
    {
        m_factories[typeId] = [typeId](World &world, uint64_t id, const uint8_t *data, size_t size) -> std::shared_ptr<Entity>
        {
            std::shared_ptr<Entity> entity = std::make_shared<TEntity>(world, typeId, id);
            if (data != nullptr) entity->deserializeState(data, size);
            return entity;
        };
    }

public:
    /**
     * @brief Register all entity types.
     */
    void registerAllEntities();

    /**
     * @brief Create an entity.
     * 
     * @param world The world.
     * @param typeId The type ID.
     * @param id Entity ID.
     * @param data Entity data (may be `nullptr`).
     * @param size The entity data size.
     * @return Shared pointer to the entity or `nullptr` if failed.
     */
    std::shared_ptr<Entity> createEntity(World &world, std::string typeId, uint64_t id, const uint8_t *data, size_t size);
};

extern EntityRegistry entityRegistry;

#endif