import { Agent } from 'undici';
import { TIMEOUT_SOCKET_DEFAULT_MS, TIMEOUT_SOCKET_LOCAL_DEFAULT_MS, } from '../constants.js';
import { getModelContextLimit } from '../models/index.js';
import { getLogger } from '../utils/logging/index.js';
import { isLocalURL } from '../utils/url-utils.js';
import { handleChat } from './chat/chat-handler.js';
import { createProvider, } from './providers/provider-factory.js';
import { getTlsConnectOptions } from './tls-config.js';
export class AISDKClient {
    // Definite-assignment: populated by the async `create()` factory before
    // the client is handed to callers. The constructor only does sync setup.
    provider;
    currentModel;
    availableModels;
    providerConfig;
    undiciAgent;
    cachedContextSize;
    maxRetries;
    constructor(providerConfig) {
        const logger = getLogger();
        this.providerConfig = providerConfig;
        this.availableModels = providerConfig.models;
        this.currentModel = providerConfig.models[0] || '';
        this.cachedContextSize = 0;
        // Default to 2 retries (same as AI SDK default), or use configured value
        this.maxRetries = providerConfig.maxRetries ?? 2;
        logger.info('AI SDK client initializing', {
            models: this.availableModels,
            defaultModel: this.currentModel,
            provider: providerConfig.name || 'unknown',
            baseUrl: providerConfig.config.baseURL ? '[REDACTED]' : undefined,
            maxRetries: this.maxRetries,
        });
        const { connectionPool } = this.providerConfig;
        const { requestTimeout, socketTimeout } = this.providerConfig;
        const effectiveSocketTimeout = socketTimeout ?? requestTimeout;
        const isLocal = providerConfig.config.baseURL &&
            isLocalURL(providerConfig.config.baseURL);
        const defaultTimeout = isLocal
            ? TIMEOUT_SOCKET_LOCAL_DEFAULT_MS
            : TIMEOUT_SOCKET_DEFAULT_MS;
        const resolvedSocketTimeout = effectiveSocketTimeout === -1
            ? 0
            : (effectiveSocketTimeout ?? defaultTimeout);
        this.undiciAgent = new Agent({
            connect: {
                timeout: resolvedSocketTimeout,
                ...getTlsConnectOptions(this.providerConfig),
            },
            bodyTimeout: resolvedSocketTimeout,
            headersTimeout: resolvedSocketTimeout,
            keepAliveTimeout: connectionPool?.idleTimeout,
            keepAliveMaxTimeout: connectionPool?.cumulativeMaxIdleTimeout,
        });
        // Fetch context size asynchronously (don't block construction)
        void this.updateContextSize();
    }
    /**
     * Fetch and cache context size from models.dev
     */
    async updateContextSize() {
        const logger = getLogger();
        try {
            const contextSize = await getModelContextLimit(this.currentModel, {
                providerConfig: this.providerConfig,
            });
            this.cachedContextSize = contextSize || 0;
        }
        catch (error) {
            logger.debug('Failed to get model context size', {
                model: this.currentModel,
                error,
            });
            this.cachedContextSize = 0;
        }
    }
    static async create(providerConfig) {
        const client = new AISDKClient(providerConfig);
        // Async provider creation — lazily loads only the SDK package the
        // configured `sdkProvider` actually needs.
        client.provider = await createProvider(client.providerConfig, client.undiciAgent);
        return client;
    }
    setModel(model) {
        const logger = getLogger();
        const previousModel = this.currentModel;
        this.currentModel = model;
        logger.info('Model changed', {
            previousModel,
            newModel: model,
            provider: this.providerConfig.name,
        });
        // Update context size when model changes
        void this.updateContextSize();
    }
    getCurrentModel() {
        return this.currentModel;
    }
    getProviderConfig() {
        return this.providerConfig;
    }
    getContextSize() {
        return this.cachedContextSize;
    }
    getMaxRetries() {
        return this.maxRetries;
    }
    getAvailableModels() {
        return Promise.resolve(this.availableModels);
    }
    /**
     * Stream chat with real-time token updates
     */
    async chat(messages, tools, callbacks, signal, modeOverrides) {
        // Get the language model instance from the tagged provider.
        // GitHub Copilot requires routing: GPT-5+ → Responses API, others → Chat Completions.
        // ChatGPT/Codex always uses the Responses API.
        const model = (() => {
            switch (this.provider.kind) {
                case 'chatgpt-codex':
                    return this.provider.provider.responses(this.currentModel);
                case 'github-copilot':
                    return this.currentModel.includes('gpt-5')
                        ? this.provider.provider.responses(this.currentModel)
                        : this.provider.provider.chat(this.currentModel);
                case 'openai-compatible':
                case 'anthropic':
                case 'google':
                    return this.provider.provider(this.currentModel);
            }
        })();
        // Delegate to chat handler
        return await handleChat({
            model,
            currentModel: this.currentModel,
            providerConfig: this.providerConfig,
            messages,
            tools,
            callbacks,
            signal,
            maxRetries: this.maxRetries,
            modeOverrides,
        });
    }
    clearContext() {
        const logger = getLogger();
        logger.debug('AI SDK client context cleared', {
            model: this.currentModel,
            provider: this.providerConfig.name,
        });
        // No internal state to clear
        return Promise.resolve();
    }
    getTimeout() {
        return (this.providerConfig.socketTimeout ?? this.providerConfig.requestTimeout);
    }
}
//# sourceMappingURL=ai-sdk-client.js.map