import { registerApiProvider, } from "@earendil-works/pi-ai/compat";
import { registerOAuthProvider } from "@earendil-works/pi-ai/oauth";
import { warnDeprecation } from "../utils/deprecation.js";
import { normalizeContextWindowOptions, validateContextWindowValue } from "./context-window.js";
import { applyModelOverride } from "./model-registry-builtins.js";
import { isLegacyEnvVarNameConfigValue } from "./resolve-config-value.js";
function validateContextWindowOptions(providerName, modelId, options) {
    for (const option of options ?? []) {
        if (validateContextWindowValue(option)) {
            throw new Error(`Provider ${providerName}, model ${modelId}: invalid contextWindowOptions value`);
        }
    }
}
function migrateLegacyRegisterProviderConfigValue(providerName, field, value) {
    if (!isLegacyEnvVarNameConfigValue(value) || process.env[value] === undefined)
        return value;
    warnDeprecation(`registerProvider("${providerName}") ${field} value "${value}" is treated as a legacy environment variable reference. This will no longer be detected as an environment variable reference in a future release. Pass "$${value}" instead.`);
    return `$${value}`;
}
function migrateLegacyRegisterProviderHeaders(providerName, field, headers) {
    if (!headers)
        return undefined;
    let migratedHeaders;
    for (const [key, value] of Object.entries(headers)) {
        const migratedValue = migrateLegacyRegisterProviderConfigValue(providerName, `${field} header "${key}"`, value);
        if (migratedValue === value)
            continue;
        migratedHeaders ??= { ...headers };
        migratedHeaders[key] = migratedValue;
    }
    return migratedHeaders ?? headers;
}
export function migrateLegacyRegisterProviderConfigValues(providerName, config) {
    let migratedConfig;
    const setMigratedConfigValue = (key, value) => {
        migratedConfig ??= { ...config };
        migratedConfig[key] = value;
    };
    if (config.apiKey) {
        const apiKey = migrateLegacyRegisterProviderConfigValue(providerName, "apiKey", config.apiKey);
        if (apiKey !== config.apiKey) {
            setMigratedConfigValue("apiKey", apiKey);
        }
    }
    const headers = migrateLegacyRegisterProviderHeaders(providerName, "headers", config.headers);
    if (headers !== config.headers) {
        setMigratedConfigValue("headers", headers);
    }
    if (config.models) {
        let models;
        for (let index = 0; index < config.models.length; index++) {
            const model = config.models[index];
            const modelHeaders = migrateLegacyRegisterProviderHeaders(providerName, `model "${model.id}" headers`, model.headers);
            if (modelHeaders === model.headers)
                continue;
            models ??= [...config.models];
            models[index] = { ...model, headers: modelHeaders };
        }
        if (models) {
            setMigratedConfigValue("models", models);
        }
    }
    return migratedConfig ?? config;
}
export function validateProviderConfig(providerName, config) {
    if (config.streamSimple && !config.api) {
        throw new Error(`Provider ${providerName}: "api" is required when registering streamSimple.`);
    }
    if (!config.models || config.models.length === 0) {
        return;
    }
    if (!config.baseUrl) {
        throw new Error(`Provider ${providerName}: "baseUrl" is required when defining models.`);
    }
    if (!config.apiKey && !config.oauth) {
        throw new Error(`Provider ${providerName}: "apiKey" or "oauth" is required when defining models.`);
    }
    for (const modelDef of config.models) {
        const api = modelDef.api || config.api;
        if (!api) {
            throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified.`);
        }
        if (validateContextWindowValue(modelDef.contextWindow)) {
            throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);
        }
        validateContextWindowOptions(providerName, modelDef.id, modelDef.contextWindowOptions);
        if (modelDef.maxTokens <= 0) {
            throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);
        }
    }
}
export function applyProviderConfigToModels(input) {
    const { providerName, config, authStorage, modelOverrides, storeProviderRequestConfig, storeModelHeaders } = input;
    let models = input.models;
    if (config.oauth) {
        const oauthProvider = {
            ...config.oauth,
            id: providerName,
        };
        registerOAuthProvider(oauthProvider);
    }
    if (config.streamSimple) {
        const streamSimple = config.streamSimple;
        registerApiProvider({
            api: config.api,
            stream: (model, context, options) => streamSimple(model, context, options),
            streamSimple,
        }, `provider:${providerName}`);
    }
    storeProviderRequestConfig(providerName, config);
    if (config.models && config.models.length > 0) {
        models = models.filter((m) => m.provider !== providerName);
        for (const modelDef of config.models) {
            const api = modelDef.api || config.api;
            const modelOverride = modelOverrides.get(providerName)?.get(modelDef.id);
            storeModelHeaders(providerName, modelDef.id, {
                ...modelDef.headers,
                ...modelOverride?.headers,
            });
            const model = {
                id: modelDef.id,
                name: modelDef.name,
                api: api,
                provider: providerName,
                baseUrl: modelDef.baseUrl ?? config.baseUrl,
                reasoning: modelDef.reasoning,
                thinkingLevelMap: modelDef.thinkingLevelMap,
                input: modelDef.input,
                cost: modelDef.cost,
                contextWindow: modelDef.contextWindow,
                defaultContextWindow: modelDef.contextWindow,
                contextWindowOptions: normalizeContextWindowOptions([
                    modelDef.contextWindow,
                    ...(modelDef.contextWindowOptions ?? []),
                ]),
                maxTokens: modelDef.maxTokens,
                headers: undefined,
                compat: modelDef.compat,
            };
            models.push(modelOverride ? applyModelOverride(model, modelOverride) : model);
        }
        if (config.oauth?.modifyModels) {
            const cred = authStorage.get(providerName);
            if (cred?.type === "oauth") {
                models = config.oauth.modifyModels(models, cred);
            }
        }
    }
    else if (config.baseUrl || config.headers) {
        models = models.map((m) => {
            if (m.provider !== providerName)
                return m;
            return {
                ...m,
                baseUrl: config.baseUrl ?? m.baseUrl,
            };
        });
    }
    return models;
}
//# sourceMappingURL=model-registry-dynamic.js.map