/**
 * Module Registry
 * Manages module registration and dependency tracking
 */
export class ModuleRegistry {
    constructor() {
        this.modules = {};
        this.readyPromises = {};
        this.moduleDependencies = new Map(); // Track module dependencies
    }
    
    /**
     * Register a module
     * @param {BaseModule} module - Module to register
     * @param {Array<string>} [dependencies] - Optional array of module dependencies
     */
    register(module, dependencies = null) {
        if (!module || !module.id) {
            console.error('Invalid module - must have an id property');
            return;
        }
        
        // Store the module
        this.modules[module.id] = module;
        
        // Store dependencies if provided, otherwise use module.dependencies
        if (dependencies) {
            this.moduleDependencies.set(module.id, dependencies);
            
            // Mirror explicit dependencies onto the module instance.
            if (module.dependencies === undefined) {
                module.dependencies = [...dependencies];
            }
        } else if (module.dependencies) {
            // Use the module's own dependencies property
            this.moduleDependencies.set(module.id, [...module.dependencies]);
        } else {
            // No dependencies
            this.moduleDependencies.set(module.id, []);
        }
        
        // Create a promise that will resolve when this module is ready
        this.readyPromises[module.id] = new Promise((resolve) => {
            // Set up a state change listener for this module
            document.addEventListener('module:stateChange', (event) => {
                if (event.detail.moduleId === module.id && 
                   (event.detail.state === 'FINISHED' || event.detail.state === 'ERROR')) {
                    resolve(event.detail.state === 'FINISHED');
                }
            });
            
            // Check if already in finished state
            if (module.state === 'FINISHED') {
                resolve(true);
            } else if (module.state === 'ERROR') {
                resolve(false);
            }
        });
    }
        
    /**
     * Get a module by id
     * @param {string} id - Module id
     * @returns {BaseModule} - The module, or null if not found
     */
    getModule(id) {
        return this.modules[id] || null;
    }
    
    /**
     * Get all registered modules
     * @returns {Object} - Map of modules
     */
    getAllModules() {
        return this.modules;
    }
    
    /**
     * Get dependencies for a module
     * @param {string} id - Module id
     * @returns {Array<string>} - Array of dependencies
     */
    getDependencies(id) {
        return this.moduleDependencies.get(id) || [];
    }
       
    /**
     * Wait for a module to be ready (in FINISHED state)
     * @param {string} id - Module id to wait for
     * @param {number} timeout - Optional timeout in ms
     * @returns {Promise} - Resolves when the module is ready
     */
    waitForModule(id, timeout = null) {
        if (!this.readyPromises[id]) {
            return Promise.resolve(false);
        }
        
        if (timeout) {
            // Add timeout logic
            return Promise.race([
                this.readyPromises[id],
                new Promise(resolve => setTimeout(() => resolve(false), timeout))
            ]);
        }
        
        return this.readyPromises[id];
    }
    
    /**
     * Wait for multiple modules to be ready
     * @param {Array<string>} ids - Array of module ids to wait for
     * @param {number} timeout - Optional timeout in ms
     * @returns {Promise} - Resolves when all modules are ready
     */
    waitForModules(ids, timeout = null) {
        const promises = ids.map(id => this.waitForModule(id, timeout));
        return Promise.all(promises);
    }
}

// Create and export a singleton instance
export const moduleRegistry = new ModuleRegistry();

// Make registry accessible globally
window.moduleRegistry = moduleRegistry;
