/**
 * Provider Registry — manages ExternalProvider registrations
 *
 * Provides a central registry for external sync providers (GitHub, Linear, etc.).
 * Supports registration, lookup by name, listing all providers, and querying
 * providers by adapter type.
 *
 * Usage:
 * ```typescript
 * import { createProviderRegistry } from '@stoneforge/quarry';
 *
 * const registry = createProviderRegistry();
 * registry.register(myProvider);
 * const github = registry.get('github');
 * const taskProviders = registry.getAdaptersOfType('task');
 * ```
 */
import { createGitHubProvider, createGitHubPlaceholderProvider } from './providers/github/index.js';
import { createLinearProvider, createLinearPlaceholderProvider } from './providers/linear/index.js';
import { createNotionProvider, createNotionPlaceholderProvider } from './providers/notion/index.js';
import { createFolderProvider } from './providers/folder/index.js';
// ============================================================================
// ProviderRegistry
// ============================================================================
/**
 * Registry for external sync providers.
 *
 * Manages registration and lookup of ExternalProvider instances.
 * Providers are keyed by their `name` property (e.g., 'github', 'linear').
 */
export class ProviderRegistry {
    providers = new Map();
    /**
     * Register a provider.
     *
     * @param provider - The provider to register
     * @throws Error if a provider with the same name is already registered
     */
    register(provider) {
        if (this.providers.has(provider.name)) {
            throw new Error(`Provider '${provider.name}' is already registered. ` +
                `Unregister it first or use a different name.`);
        }
        this.providers.set(provider.name, provider);
    }
    /**
     * Look up a provider by name.
     *
     * @param name - The provider name (e.g., 'github')
     * @returns The provider, or undefined if not found
     */
    get(name) {
        return this.providers.get(name);
    }
    /**
     * List all registered providers.
     *
     * @returns Array of all registered providers
     */
    list() {
        return Array.from(this.providers.values());
    }
    /**
     * Find all providers that support a given adapter type, and return
     * the provider paired with its adapter for that type.
     *
     * @param type - The adapter type to filter by ('task', 'document', 'message')
     * @returns Array of { provider, adapter } for all matching providers
     */
    getAdaptersOfType(type) {
        const results = [];
        for (const provider of this.providers.values()) {
            if (!provider.supportedAdapters.includes(type)) {
                continue;
            }
            const adapter = getAdapterByType(provider, type);
            if (adapter) {
                results.push({ provider, adapter });
            }
        }
        return results;
    }
    /**
     * Check if a provider is registered.
     *
     * @param name - The provider name
     * @returns true if the provider is registered
     */
    has(name) {
        return this.providers.has(name);
    }
    /**
     * Unregister a provider by name.
     *
     * @param name - The provider name to remove
     * @returns true if the provider was removed, false if not found
     */
    unregister(name) {
        return this.providers.delete(name);
    }
    /**
     * Remove all registered providers.
     */
    clear() {
        this.providers.clear();
    }
}
// ============================================================================
// Helper Functions
// ============================================================================
/**
 * Get the adapter from a provider for a given adapter type.
 */
function getAdapterByType(provider, type) {
    switch (type) {
        case 'task':
            return provider.getTaskAdapter?.();
        case 'document':
            return provider.getDocumentAdapter?.();
        case 'message':
            return provider.getMessageAdapter?.();
        default:
            return undefined;
    }
}
// ============================================================================
// Factory
// ============================================================================
/**
 * Create a new ProviderRegistry instance.
 *
 * @returns A new, empty ProviderRegistry
 */
export function createProviderRegistry() {
    return new ProviderRegistry();
}
/**
 * Create a ProviderRegistry with default providers registered.
 *
 * Registers placeholder providers for GitHub, Linear, and Notion by default,
 * plus the Folder provider (which needs no authentication and is always ready).
 * The actual provider implementations replace placeholders when configured with API keys.
 *
 * @returns A ProviderRegistry with default providers
 */
export function createDefaultProviderRegistry() {
    const registry = new ProviderRegistry();
    registry.register(createGitHubPlaceholderProvider());
    registry.register(createLinearPlaceholderProvider());
    registry.register(createNotionPlaceholderProvider());
    registry.register(createFolderProvider());
    return registry;
}
/**
 * Create a ProviderRegistry with real configured providers.
 *
 * Starts with placeholder providers for all known providers (GitHub, Linear, Notion, Folder),
 * then replaces placeholders with real configured providers for any configs
 * that have a token set. This ensures providers without tokens remain as
 * placeholders (which throw descriptive errors), while configured providers
 * are ready for actual sync operations.
 *
 * Note: The Folder provider is always ready (no token needed), so it is
 * never replaced — it remains as-is from the default registry.
 *
 * @param providerConfigs - Array of provider configurations (from settings)
 * @returns A ProviderRegistry with configured providers replacing placeholders
 */
export function createConfiguredProviderRegistry(providerConfigs) {
    const registry = createDefaultProviderRegistry();
    for (const config of providerConfigs) {
        // Folder provider doesn't need a token — it's always ready
        if (config.provider === 'folder') {
            continue;
        }
        if (!config.token) {
            continue;
        }
        // Replace the placeholder with a real configured provider
        registry.unregister(config.provider);
        switch (config.provider) {
            case 'github':
                registry.register(createGitHubProvider({
                    provider: 'github',
                    token: config.token,
                    apiBaseUrl: config.apiBaseUrl,
                    defaultProject: config.defaultProject,
                }));
                break;
            case 'linear':
                registry.register(createLinearProvider({
                    apiKey: config.token,
                }));
                break;
            case 'notion':
                registry.register(createNotionProvider({
                    token: config.token,
                }));
                break;
            // Unknown providers are silently skipped — their placeholders remain
        }
    }
    return registry;
}
//# sourceMappingURL=provider-registry.js.map