/**
 * @license
 * Copyright 2025 OElite Platform
 * SPDX-License-Identifier: Apache-2.0
 */
import { AuthMethod, ProviderType } from './types.js';
import { AnthropicProvider } from './anthropicProvider.js';
import { AzureProvider } from './azureProvider.js';
import { BedrockProvider } from './bedrockProvider.js';
import { OllamaProvider } from './ollamaProvider.js';
import { getProviderMetadata } from './providerMetadata.js';
import { modelCatalog } from './modelCatalog.js';
/**
 * Provider registry for managing multiple AI providers
 */
export class ProviderRegistry {
    providers = new Map();
    factories = new Map();
    currentProvider;
    constructor() {
        this.registerDefaultFactories();
    }
    /**
     * Register default provider factories
     */
    registerDefaultFactories() {
        this.registerFactory(ProviderType.ANTHROPIC, (config) => new AnthropicProvider(config));
        this.registerFactory(ProviderType.AZURE, (config) => new AzureProvider(config));
        this.registerFactory(ProviderType.AWS_BEDROCK, (config) => new BedrockProvider(config));
        this.registerFactory(ProviderType.OLLAMA, (config) => new OllamaProvider(config));
    }
    /**
     * Register a provider factory
     */
    registerFactory(type, factory) {
        this.factories.set(type, factory);
    }
    /**
     * Register a provider instance
     */
    async registerProvider(type, config) {
        const factory = this.factories.get(type);
        if (!factory) {
            throw new Error(`No factory registered for provider type: ${type}`);
        }
        const provider = factory(config);
        await provider.initialize();
        this.providers.set(type, provider);
        if (!this.currentProvider) {
            this.currentProvider = type;
        }
        return provider;
    }
    /**
     * Get a registered provider
     */
    getProvider(type) {
        return this.providers.get(type);
    }
    /**
     * Get current active provider
     */
    getCurrentProvider() {
        if (!this.currentProvider)
            return undefined;
        return this.providers.get(this.currentProvider);
    }
    /**
     * Set current provider
     */
    setCurrentProvider(type) {
        if (!this.providers.has(type)) {
            throw new Error(`Provider ${type} not registered. Register it first before setting as current.`);
        }
        this.currentProvider = type;
    }
    /**
     * Get all registered providers
     */
    getAllProviders() {
        return Array.from(this.providers.values());
    }
    /**
     * Get all configured providers (from environment)
     */
    async discoverProvidersFromEnv() {
        const discovered = [];
        for (const type of Object.values(ProviderType)) {
            const metadata = getProviderMetadata(type);
            if (!metadata)
                continue;
            // Check if provider has required environment variables
            let hasRequiredEnv = false;
            if (metadata.envVars.apiKey) {
                for (const envVar of metadata.envVars.apiKey) {
                    if (process.env[envVar]) {
                        hasRequiredEnv = true;
                        break;
                    }
                }
            }
            // Special cases
            if (type === ProviderType.OLLAMA) {
                // Only discover Ollama if explicitly configured via OLLAMA_BASE_URL
                // Don't auto-discover just because it doesn't need an API key
                hasRequiredEnv = !!process.env['OLLAMA_BASE_URL'];
            }
            if (type === ProviderType.AWS_BEDROCK) {
                // AWS Bedrock needs AWS credentials
                hasRequiredEnv =
                    !!process.env['AWS_ACCESS_KEY_ID'] &&
                        !!process.env['AWS_SECRET_ACCESS_KEY'];
            }
            if (hasRequiredEnv) {
                discovered.push(type);
            }
        }
        return discovered;
    }
    /**
     * Auto-initialize all configured providers from environment
     */
    async autoInitializeProviders() {
        const results = new Map();
        const discovered = await this.discoverProvidersFromEnv();
        for (const type of discovered) {
            try {
                const config = {
                    type,
                    name: type,
                    enabled: true,
                    authMethod: getProviderMetadata(type)?.defaultAuthMethod || AuthMethod.API_KEY,
                };
                await this.registerProvider(type, config);
                results.set(type, true);
                // Silently succeed - no need to log successful initialization
            }
            catch (error) {
                results.set(type, false);
                console.error(`✗ Failed to initialize provider ${type}:`, error instanceof Error ? error.message : String(error));
            }
        }
        return results;
    }
    /**
     * Check health of all registered providers
     */
    async checkAllProvidersHealth() {
        const healthResults = new Map();
        for (const [type, provider] of this.providers.entries()) {
            try {
                const health = await provider.checkHealth();
                healthResults.set(type, health);
            }
            catch (error) {
                healthResults.set(type, {
                    provider: type,
                    isHealthy: false,
                    lastChecked: new Date(),
                    error: error instanceof Error ? error.message : String(error),
                });
            }
        }
        return healthResults;
    }
    /**
     * Get all available models from all providers
     */
    async getAllAvailableModels() {
        const allModels = [];
        for (const provider of this.providers.values()) {
            try {
                const models = await provider.getAvailableModels();
                allModels.push(...models);
            }
            catch (error) {
                console.error(`Error getting models from ${provider.type}:`, error instanceof Error ? error.message : String(error));
            }
        }
        return allModels;
    }
    /**
     * Find best model matching criteria
     */
    async findBestModel(criteria) {
        let availableModels = await this.getAllAvailableModels();
        // Filter by provider preferences
        if (criteria.preferredProviders && criteria.preferredProviders.length > 0) {
            availableModels = availableModels.filter((m) => criteria.preferredProviders.includes(m.provider));
        }
        if (criteria.excludedProviders && criteria.excludedProviders.length > 0) {
            availableModels = availableModels.filter((m) => !criteria.excludedProviders.includes(m.provider));
        }
        // Filter by capabilities
        if (criteria.requiresVision) {
            availableModels = availableModels.filter((m) => m.capabilities.supportsVision);
        }
        if (criteria.requiresThinking) {
            availableModels = availableModels.filter((m) => m.capabilities.supportsThinking);
        }
        if (criteria.minContextWindow) {
            availableModels = availableModels.filter((m) => m.capabilities.contextWindow &&
                m.capabilities.contextWindow >= criteria.minContextWindow);
        }
        // Filter by cost
        if (criteria.maxCost) {
            availableModels = availableModels.filter((m) => !m.pricing || (m.pricing.inputPrice || 0) <= criteria.maxCost);
        }
        // Sort by cost (cheapest first)
        availableModels.sort((a, b) => {
            const priceA = a.pricing?.inputPrice || 0;
            const priceB = b.pricing?.inputPrice || 0;
            return priceA - priceB;
        });
        return availableModels[0] || null;
    }
    /**
     * Get provider for a specific model
     */
    getProviderForModel(modelId) {
        for (const provider of this.providers.values()) {
            // Check if model exists in this provider
            const model = modelCatalog.getModel(modelId);
            if (model && model.provider === provider.type) {
                return provider;
            }
        }
        return undefined;
    }
    /**
     * Unregister a provider
     */
    unregisterProvider(type) {
        this.providers.delete(type);
        if (this.currentProvider === type) {
            // Set next available provider as current
            const providers = Array.from(this.providers.keys());
            this.currentProvider = providers[0];
        }
    }
    /**
     * Clear all providers
     */
    clear() {
        this.providers.clear();
        this.currentProvider = undefined;
    }
    /**
     * Get provider statistics
     */
    getStatistics() {
        return {
            totalProviders: this.factories.size,
            configuredProviders: this.providers.size,
            currentProvider: this.currentProvider,
            availableProviders: Array.from(this.providers.keys()),
        };
    }
}
// Export singleton instance
export const providerRegistry = new ProviderRegistry();
//# sourceMappingURL=providerRegistry.js.map