#include <extra2d/core/registry.h>
#include <extra2d/utils/logger.h>
#include <algorithm>
#include <queue>
#include <unordered_set>
#include <iostream>

namespace extra2d {

Registry& Registry::instance() {
    static Registry instance;
    return instance;
}

bool Registry::init() {
    auto sorted = topologicalSort();

    std::cout << "[Registry] Initializing " << sorted.size() << " modules..." << std::endl;

    for (auto* module : sorted) {
        std::cout << "[Registry] Initializing module: " << module->name() << std::endl;
        if (!module->init()) {
            std::cerr << "[Registry] Failed to initialize module: " << module->name() << std::endl;
            return false;
        }
        std::cout << "[Registry] Module " << module->name() << " initialized successfully" << std::endl;
    }

    std::cout << "[Registry] All modules initialized" << std::endl;
    return true;
}

void Registry::shutdown() {
    auto sorted = topologicalSort();
    
    // 反向关闭
    for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) {
        (*it)->shutdown();
    }
}

void Registry::clear() {
    shutdown();
    modules_.clear();
}

std::vector<Module*> Registry::topologicalSort() {
    std::vector<Module*> result;
    std::unordered_map<Module*, int> inDegree;
    std::unordered_map<Module*, std::vector<Module*>> adj;
    
    // 构建图
    for (auto& [typeIdx, module] : modules_) {
        inDegree[module.get()] = 0;
    }
    
    for (auto& [typeIdx, module] : modules_) {
        for (auto& depType : module->deps()) {
            Module* dep = get(depType);
            if (dep) {
                adj[dep].push_back(module.get());
                inDegree[module.get()]++;
            }
        }
    }
    
    // 优先级队列（优先级小的先处理）
    auto cmp = [](Module* a, Module* b) {
        return a->priority() > b->priority();
    };
    std::priority_queue<Module*, std::vector<Module*>, decltype(cmp)> pq(cmp);
    
    for (auto& [mod, degree] : inDegree) {
        if (degree == 0) {
            pq.push(mod);
        }
    }
    
    // 拓扑排序
    while (!pq.empty()) {
        Module* curr = pq.top();
        pq.pop();
        result.push_back(curr);
        
        for (Module* next : adj[curr]) {
            inDegree[next]--;
            if (inDegree[next] == 0) {
                pq.push(next);
            }
        }
    }
    
    return result;
}

} // namespace extra2d
