import { fetch as undiciFetch, } from 'undici';
import { getValidCodexToken } from '../../auth/chatgpt-codex.js';
import { COPILOT_HEADERS, getCopilotAccessToken, getCopilotBaseUrl, } from '../../auth/github-copilot.js';
import { getCodexNoCredentialsMessage, loadCodexCredential, updateCodexCredential, } from '../../config/codex-credentials.js';
import { getCopilotNoCredentialsMessage, loadCopilotCredential, } from '../../config/copilot-credentials.js';
import { getLogger } from '../../utils/logging/index.js';
import { isOpenRouterProvider } from './openrouter.js';
import { isRequestyProvider } from './requesty.js';
/**
 * Wraps undici's fetch so requests flow through the shared Agent. The Agent
 * carries TLS connect options (e.g. caCertPath), so any SDK provider given
 * this fetch will honor the configured CA bundle — even Anthropic and Google,
 * which would otherwise use the global fetch and bypass our TLS settings.
 */
function createUndiciFetch(undiciAgent) {
    return (url, options) => {
        return undiciFetch(url, {
            ...options,
            dispatcher: undiciAgent,
        });
    };
}
/**
 * Creates an AI SDK provider based on the sdkProvider configuration.
 * Defaults to 'openai-compatible' if not specified.
 *
 * Async because provider SDK packages are loaded lazily — only the one that
 * matches the caller's `sdkProvider` is imported, so a session that only
 * uses Anthropic never loads the Google or OpenAI packages.
 */
export async function createProvider(providerConfig, undiciAgent) {
    const logger = getLogger();
    const { config, sdkProvider } = providerConfig;
    // Use explicit sdkProvider if set, otherwise default to 'openai-compatible'
    if (sdkProvider === 'anthropic') {
        logger.info('Using @ai-sdk/anthropic provider', {
            provider: providerConfig.name,
            sdkProvider,
        });
        const { createAnthropic } = await import('@ai-sdk/anthropic');
        return {
            kind: 'anthropic',
            provider: createAnthropic({
                baseURL: config.baseURL || undefined,
                apiKey: config.apiKey ?? '',
                headers: config.headers,
                fetch: createUndiciFetch(undiciAgent),
            }),
        };
    }
    if (sdkProvider === 'google') {
        logger.info('Using @ai-sdk/google provider', {
            provider: providerConfig.name,
            sdkProvider,
        });
        const { createGoogleGenerativeAI } = await import('@ai-sdk/google');
        return {
            kind: 'google',
            provider: createGoogleGenerativeAI({
                apiKey: config.apiKey ?? '',
                fetch: createUndiciFetch(undiciAgent),
            }),
        };
    }
    if (sdkProvider === 'github-copilot') {
        logger.info('Using GitHub Copilot subscription provider', {
            provider: providerConfig.name,
        });
        const credential = loadCopilotCredential(providerConfig.name);
        if (!credential) {
            throw new Error(getCopilotNoCredentialsMessage(providerConfig.name));
        }
        const domain = credential.enterpriseUrl ?? 'github.com';
        const baseURL = config.baseURL?.trim() || getCopilotBaseUrl(domain);
        const copilotFetch = async (input, init) => {
            const { token } = await getCopilotAccessToken(credential.oauthToken, domain);
            // Build headers via Headers (case-insensitive) to avoid
            // duplicate keys when merging SDK lowercase and Copilot mixed-case.
            const h = new Headers();
            if (init?.headers) {
                const src = init.headers instanceof Headers
                    ? init.headers
                    : new Headers(init.headers);
                src.forEach((v, k) => {
                    if (k !== 'authorization') {
                        h.set(k, v);
                    }
                });
            }
            for (const [k, v] of Object.entries(COPILOT_HEADERS)) {
                h.set(k, v);
            }
            h.set('Authorization', `Bearer ${token}`);
            h.set('Openai-Intent', 'conversation-edits');
            h.set('X-Initiator', 'agent');
            // Convert to plain object for undici
            const headers = {};
            h.forEach((v, k) => {
                headers[k] = v;
            });
            return undiciFetch(input, {
                method: init?.method,
                body: init?.body,
                signal: init?.signal,
                headers,
                dispatcher: undiciAgent,
            });
        };
        const { createOpenAI } = await import('@ai-sdk/openai');
        return {
            kind: 'github-copilot',
            provider: createOpenAI({
                baseURL,
                // Empty key — auth is handled entirely by copilotFetch's Authorization header
                apiKey: '',
                fetch: copilotFetch,
                headers: config.headers ?? {},
            }),
        };
    }
    if (sdkProvider === 'chatgpt-codex') {
        logger.info('Using ChatGPT/Codex subscription provider', {
            provider: providerConfig.name,
        });
        const credential = loadCodexCredential(providerConfig.name);
        if (!credential) {
            throw new Error(getCodexNoCredentialsMessage(providerConfig.name));
        }
        const baseURL = config.baseURL?.trim() || 'https://chatgpt.com/backend-api/codex';
        const codexFetch = async (input, init) => {
            // Get valid token (refreshing if needed)
            const { accessToken, accountId } = await getValidCodexToken(credential, tokens => {
                updateCodexCredential(providerConfig.name, tokens);
            });
            const h = new Headers();
            if (init?.headers) {
                const src = init.headers instanceof Headers
                    ? init.headers
                    : new Headers(init.headers);
                src.forEach((v, k) => {
                    if (k !== 'authorization') {
                        h.set(k, v);
                    }
                });
            }
            h.set('Authorization', `Bearer ${accessToken}`);
            h.set('ChatGPT-Account-Id', accountId);
            h.set('originator', 'codex_cli_rs');
            // Convert to plain object for undici
            const headers = {};
            h.forEach((v, k) => {
                headers[k] = v;
            });
            // Codex backend requires store: false on every request.
            // Patch the JSON body to ensure the backend accepts it.
            let body = init?.body;
            if (body && typeof body === 'string') {
                try {
                    const parsed = JSON.parse(body);
                    parsed.store = false;
                    body = JSON.stringify(parsed);
                }
                catch {
                    // Not JSON — pass through
                }
            }
            return undiciFetch(input, {
                method: init?.method,
                body: body,
                signal: init?.signal,
                headers,
                dispatcher: undiciAgent,
            });
        };
        const { createOpenAI } = await import('@ai-sdk/openai');
        return {
            kind: 'chatgpt-codex',
            provider: createOpenAI({
                baseURL,
                apiKey: '',
                fetch: codexFetch,
                headers: config.headers ?? {},
            }),
        };
    }
    // Add OpenRouter-specific headers for app attribution
    const headers = config.headers ?? {};
    if (isOpenRouterProvider(providerConfig.name)) {
        headers['HTTP-Referer'] = 'https://github.com/Nano-Collective/nanocoder';
        headers['X-Title'] = 'Nanocoder';
    }
    // Requesty (https://requesty.ai) is an OpenAI-compatible router and uses
    // the same app-attribution headers as OpenRouter.
    if (isRequestyProvider(providerConfig.name)) {
        headers['HTTP-Referer'] = 'https://github.com/Nano-Collective/nanocoder';
        headers['X-Title'] = 'Nanocoder';
    }
    const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible');
    return {
        kind: 'openai-compatible',
        provider: createOpenAICompatible({
            name: providerConfig.name,
            baseURL: config.baseURL ?? '',
            apiKey: config.apiKey ?? 'dummy-key',
            fetch: createUndiciFetch(undiciAgent),
            headers,
        }),
    };
}
//# sourceMappingURL=provider-factory.js.map