#pragma once

#include <extra2d/core/module.h>
#include <extra2d/core/types.h>
#include <unordered_map>
#include <typeindex>
#include <vector>
#include <memory>

namespace extra2d {

class Application;

/**
 * @brief 模块注册表
 * 管理模块的注册、拓扑排序和生命周期
 */
class Registry {
public:
    static Registry& instance();
    
    Registry(const Registry&) = delete;
    Registry& operator=(const Registry&) = delete;
    
    /**
     * @brief 注册模块
     * @tparam T 模块类型
     * @tparam Args 构造函数参数类型
     * @param args 构造函数参数
     * @return 模块指针
     */
    template<typename T, typename... Args>
    T* use(Args&&... args) {
        static_assert(std::is_base_of_v<Module, T>, "T must derive from Module");
        
        auto typeIdx = std::type_index(typeid(T));
        if (modules_.count(typeIdx)) {
            return static_cast<T*>(modules_[typeIdx].get());
        }
        
        auto module = makeUnique<T>(std::forward<Args>(args)...);
        T* ptr = module.get();
        module->setApp(app_);
        modules_[typeIdx] = std::move(module);
        return ptr;
    }
    
    /**
     * @brief 获取模块
     * @tparam T 模块类型
     * @return 模块指针，不存在返回 nullptr
     */
    template<typename T>
    T* get() const {
        auto typeIdx = std::type_index(typeid(T));
        auto it = modules_.find(typeIdx);
        if (it != modules_.end()) {
            return static_cast<T*>(it->second.get());
        }
        return nullptr;
    }
    
    /**
     * @brief 获取模块（基类版本）
     * @param typeIdx 类型索引
     * @return 模块指针
     */
    Module* get(std::type_index typeIdx) const {
        auto it = modules_.find(typeIdx);
        if (it != modules_.end()) {
            return it->second.get();
        }
        return nullptr;
    }
    
    /**
     * @brief 设置Application
     */
    void setApp(Application* app) { app_ = app; }
    
    /**
     * @brief 初始化所有模块（按优先级拓扑排序）
     * @return 初始化成功返回 true
     */
    bool init();
    
    /**
     * @brief 关闭所有模块
     */
    void shutdown();
    
    /**
     * @brief 清空所有模块
     */
    void clear();
    
    /**
     * @brief 获取模块数量
     */
    size_t size() const { return modules_.size(); }

private:
    Registry() = default;
    ~Registry() = default;
    
    /**
     * @brief 拓扑排序模块
     * @return 排序后的模块列表
     */
    std::vector<Module*> topologicalSort();
    
    std::unordered_map<std::type_index, UniquePtr<Module>> modules_;
    Application* app_ = nullptr;
};

} // namespace extra2d
