// ✅ CIRCULAR DEPENDENCY FIX: Remove barrel export import
// Providers are now managed via ProviderFactory instead of direct imports
import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
import { tracers } from "../telemetry/tracers.js";
import { ProviderFactory } from "../factories/providerFactory.js";
import { ProviderRegistry } from "../factories/providerRegistry.js";
import { getBestProvider } from "../utils/providerUtils.js";
import { logger } from "../utils/logger.js";
import { dynamicModelProvider } from "./dynamicModels.js";
import { withTimeout, ErrorFactory } from "../utils/errorHandling.js";
import { AIProviderName } from "../constants/enums.js";
const componentIdentifier = "aiProviderFactory";
const factoryTracer = tracers.factory;
/**
 * Factory for creating AI provider instances with centralized configuration
 */
export class AIProviderFactory {
    /**
     * Normalize provider name using ProviderFactory
     */
    static normalizeProviderName(providerName) {
        // Use ProviderFactory registration - no more legacy switch statements
        const normalized = ProviderFactory.normalizeProviderName(providerName);
        if (normalized) {
            return normalized;
        }
        // If not found in factory, return as-is (will be handled by factory error handling)
        return providerName.toLowerCase();
    }
    /**
     * Initialize dynamic model provider with timeout protection
     * Prevents hanging on non-responsive endpoints
     */
    static async initializeDynamicProviderWithTimeout() {
        const functionTag = "AIProviderFactory.initializeDynamicProviderWithTimeout";
        const INIT_TIMEOUT = 10000; // 10 seconds total timeout for initialization
        try {
            await withTimeout(dynamicModelProvider.initialize(), INIT_TIMEOUT, ErrorFactory.toolTimeout("dynamic-provider-init", INIT_TIMEOUT));
            logger.debug(`[${functionTag}] Dynamic model provider initialized successfully`);
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            logger.warn(`[${functionTag}] Dynamic model provider initialization failed`, {
                error: errorMessage,
                fallback: "Using static model defaults",
            });
            // Don't throw - graceful degradation to static models
            // This ensures the factory continues to work even if dynamic models fail
        }
    }
    static resolveModelFromEnvironment(providerName, modelName, functionTag) {
        if (modelName && modelName !== "default") {
            logger.debug(`[${functionTag}] Skipping environment variable check - explicit model provided: ${modelName}`);
            return modelName;
        }
        logger.debug(`[${functionTag}] Checking environment variables for provider: ${providerName}`);
        const normalizedProvider = providerName.toLowerCase();
        const envConfigs = [
            {
                match: ["bedrock"],
                label: "Bedrock",
                vars: ["BEDROCK_MODEL", "BEDROCK_MODEL_ID"],
            },
            {
                match: ["vertex"],
                label: "Vertex",
                vars: ["VERTEX_MODEL"],
            },
            {
                match: ["azure"],
                label: "Azure",
                vars: [
                    "AZURE_OPENAI_MODEL",
                    "AZURE_OPENAI_DEPLOYMENT",
                    "AZURE_OPENAI_DEPLOYMENT_ID",
                ],
            },
            {
                match: ["openai", "gpt", "chatgpt", "openai-compat"],
                label: "OpenAI",
                vars: ["OPENAI_MODEL"],
            },
            {
                match: ["anthropic", "claude", "anthropic-claude"],
                label: "Anthropic",
                vars: ["ANTHROPIC_MODEL"],
            },
            {
                match: ["google", "gemini"],
                label: "Google AI",
                vars: ["GOOGLE_AI_MODEL"],
            },
            {
                match: ["mistral"],
                label: "Mistral",
                vars: ["MISTRAL_MODEL"],
            },
            {
                match: ["ollama"],
                label: "Ollama",
                vars: ["OLLAMA_MODEL"],
            },
            {
                match: ["litellm"],
                label: "LiteLLM",
                vars: ["LITELLM_MODEL"],
            },
        ];
        const envConfig = envConfigs.find((config) => config.match.some((match) => normalizedProvider.includes(match)));
        if (!envConfig) {
            logger.debug(`[${functionTag}] Provider ${providerName} - no environment variable check implemented`);
            return modelName;
        }
        const matchedVar = envConfig.vars.find((name) => process.env[name]);
        const envModel = matchedVar ? process.env[matchedVar] : undefined;
        if (envModel) {
            logger.debug(`[${functionTag}] Environment variable found for ${envConfig.label}`, {
                envVariable: matchedVar,
                resolvedModel: envModel,
            });
            return envModel;
        }
        logger.debug(`[${functionTag}] No ${envConfig.label} environment variables found (${envConfig.vars.join(", ")})`);
        return modelName;
    }
    static async resolveDynamicModelName(providerName, modelName, resolvedModelName, functionTag) {
        if ((resolvedModelName && resolvedModelName !== "default") ||
            (modelName && modelName !== "default")) {
            logger.debug(`[${functionTag}] Skipping dynamic model resolution`, {
                resolvedModelName: resolvedModelName || "none",
                reason: "Model already resolved from environment variables or explicit parameter",
            });
            return resolvedModelName;
        }
        logger.debug(`[${functionTag}] Attempting dynamic model resolution`, {
            currentResolvedModel: resolvedModelName || "none",
            reason: "No environment variable found and no explicit model provided",
        });
        try {
            const normalizedProvider = this.normalizeProviderName(providerName);
            if (dynamicModelProvider.needsRefresh()) {
                logger.debug(`[${functionTag}] Dynamic model provider needs refresh - initializing`);
                await this.initializeDynamicProviderWithTimeout();
            }
            const dynamicModel = dynamicModelProvider.resolveModel(normalizedProvider, modelName || undefined);
            if (!dynamicModel) {
                logger.debug(`[${functionTag}] Dynamic model resolution returned null`, {
                    provider: normalizedProvider,
                    requestedModel: modelName || "default",
                });
                return resolvedModelName;
            }
            logger.debug(`[${functionTag}] Resolved dynamic model`, {
                provider: normalizedProvider,
                requestedModel: modelName || "default",
                resolvedModel: dynamicModel.id,
                displayName: dynamicModel.displayName,
                pricing: dynamicModel.pricing.input,
            });
            return dynamicModel.id;
        }
        catch (resolveError) {
            logger.debug(`[${functionTag}] Dynamic model resolution failed, using static fallback`, {
                error: resolveError instanceof Error
                    ? resolveError.message
                    : String(resolveError),
            });
            return resolvedModelName;
        }
    }
    static async createResolvedProvider(providerName, resolvedModelName, sdk, region, functionTag, credentials) {
        await withTimeout(ProviderRegistry.registerAllProviders(), 30_000, ErrorFactory.toolTimeout("provider-registration", 30_000));
        const normalizedName = this.normalizeProviderName(providerName);
        const finalModelName = resolvedModelName === "default" || resolvedModelName === null
            ? undefined
            : resolvedModelName;
        logger.debug(`[${functionTag}] Final provider configuration`, {
            originalProviderName: providerName,
            normalizedProviderName: normalizedName,
            resolvedModelName: resolvedModelName || "not resolved",
            finalModelName: finalModelName || "using provider default",
        });
        const provider = await withTimeout(ProviderFactory.createProvider(normalizedName, finalModelName, sdk, region, credentials), 30_000, ErrorFactory.toolTimeout(`provider-creation:${normalizedName}`, 30_000));
        return { normalizedName, finalModelName, provider };
    }
    /**
     * Create a provider instance for the specified provider type
     * @param providerName - Name of the provider ('vertex', 'bedrock', 'openai')
     * @param modelName - Optional model name override
     * @param enableMCP - Optional flag to enable MCP integration (default: true)
     * @param sdk - SDK instance
     * @param region - Optional region override for cloud providers
     * @returns AIProvider instance
     */
    static async createProvider(providerName, modelName, enableMCP = true, sdk, region, credentials) {
        const functionTag = "AIProviderFactory.createProvider";
        // Providers are registered via ProviderFactory.initialize() on first use
        return factoryTracer.startActiveSpan("neurolink.factory.createProvider", {
            kind: SpanKind.INTERNAL,
            attributes: {
                "provider.name": providerName,
                "model.name": modelName || "default",
                "mcp.enabled": enableMCP,
            },
        }, async (span) => {
            logger.debug(`[${functionTag}] Provider creation started`, {
                providerName,
                modelName: modelName || "default",
                enableMCP,
                environmentVariables: {
                    BEDROCK_MODEL: process.env.BEDROCK_MODEL || "not set",
                    BEDROCK_MODEL_ID: process.env.BEDROCK_MODEL_ID || "not set",
                    VERTEX_MODEL: process.env.VERTEX_MODEL || "not set",
                    OPENAI_MODEL: process.env.OPENAI_MODEL || "not set",
                },
            });
            try {
                // DYNAMIC MODEL PROVIDER STATUS (2025): Enhanced with timeout handling
                //
                // ✅ FIXED: Hanging issues resolved with comprehensive timeout implementation
                // - Added robust timeout handling (3s localhost, 5s GitHub, 1s local file)
                // - Implemented health checks for localhost endpoints
                // - Added graceful degradation when all sources fail
                // - Enhanced error handling and logging for debugging
                //
                // The dynamic model provider now provides reliable functionality without hanging
                let resolvedModelName = this.resolveModelFromEnvironment(providerName, modelName, functionTag);
                resolvedModelName = await this.resolveDynamicModelName(providerName, modelName, resolvedModelName, functionTag);
                const { normalizedName, finalModelName, provider } = await this.createResolvedProvider(providerName, resolvedModelName, sdk, region, functionTag, credentials);
                // Summary logging in format expected by debugging tools
                logger.debug(`[AIProviderFactory] Provider creation completed { providerName: '${normalizedName}', modelName: '${finalModelName}' }`);
                logger.debug(`[AIProviderFactory] Resolved model: ${finalModelName}`);
                logger.debug(componentIdentifier, "Pure factory pattern provider created", {
                    providerName: normalizedName,
                    modelName: finalModelName,
                    factoryUsed: true,
                });
                span.setAttribute("provider.resolved_name", normalizedName);
                if (finalModelName) {
                    span.setAttribute("model.resolved_name", finalModelName);
                }
                logger.debug(`[${functionTag}] Provider creation succeeded`, {
                    providerName,
                    modelName: finalModelName || "default",
                    providerType: provider.constructor.name,
                    mcpEnabled: enableMCP,
                });
                span.setStatus({ code: SpanStatusCode.OK });
                return provider;
            }
            catch (error) {
                const errorMessage = error instanceof Error ? error.message : String(error);
                span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
                span.recordException(error instanceof Error ? error : new Error(String(error)));
                logger.debug(`[${functionTag}] Provider creation failed`, {
                    providerName,
                    modelName: modelName || "default",
                    error: errorMessage,
                });
                throw error;
            }
            finally {
                span.end();
            }
        });
    }
    /**
     * Create a provider instance with specific provider enum and model
     * @param provider - Provider enum value
     * @param model - Specific model enum value
     * @returns AIProvider instance
     */
    static async createProviderWithModel(provider, model) {
        const functionTag = "AIProviderFactory.createProviderWithModel";
        logger.debug(`[${functionTag}] Provider model creation started`, {
            provider,
            model,
        });
        try {
            const providerInstance = await this.createProvider(provider, model);
            logger.debug(`[${functionTag}] Provider model creation succeeded`, {
                provider,
                model,
                providerType: providerInstance.constructor.name,
            });
            return providerInstance;
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            logger.debug(`[${functionTag}] Provider model creation failed`, {
                provider,
                model,
                error: errorMessage,
            });
            throw error;
        }
    }
    /**
     * Create the best available provider automatically
     * @param requestedProvider - Optional preferred provider
     * @param modelName - Optional model name override
     * @param enableMCP - Optional flag to enable MCP integration (default: true)
     * @returns AIProvider instance
     */
    static async createBestProvider(requestedProvider, modelName, enableMCP = true, sdk) {
        const functionTag = "AIProviderFactory.createBestProvider";
        try {
            const bestProvider = await getBestProvider(requestedProvider);
            logger.debug(`[${functionTag}] Best provider selected`, {
                requestedProvider: requestedProvider || "auto",
                selectedProvider: bestProvider,
                modelName: modelName || "default",
                enableMCP,
            });
            return await this.createProvider(bestProvider, modelName, enableMCP, sdk);
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            logger.debug(`[${functionTag}] Best provider selection failed`, {
                requestedProvider: requestedProvider || "auto",
                error: errorMessage,
            });
            throw error;
        }
    }
    /**
     * Create primary and fallback provider instances
     * @param primaryProvider - Primary provider name
     * @param fallbackProvider - Fallback provider name
     * @param modelName - Optional model name override
     * @param enableMCP - Optional flag to enable MCP integration (default: true)
     * @returns Object with primary and fallback providers
     */
    static async createProviderWithFallback(primaryProvider, fallbackProvider, modelName, enableMCP = true) {
        const functionTag = "AIProviderFactory.createProviderWithFallback";
        logger.debug(`[${functionTag}] Fallback provider setup started`, {
            primaryProvider,
            fallbackProvider,
            modelName: modelName || "default",
            enableMCP,
        });
        try {
            const primary = await this.createProvider(primaryProvider, modelName, enableMCP);
            const fallback = await this.createProvider(fallbackProvider, modelName, enableMCP);
            logger.debug(`[${functionTag}] Fallback provider setup succeeded`, {
                primaryProvider,
                fallbackProvider,
                modelName: modelName || "default",
                enableMCP,
            });
            return { primary, fallback };
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            logger.debug(`[${functionTag}] Fallback provider setup failed`, {
                primaryProvider,
                fallbackProvider,
                error: errorMessage,
            });
            throw error;
        }
    }
}
//# sourceMappingURL=factory.js.map