import { getModels, getProviders, } from "@earendil-works/pi-ai/compat";
import { normalizeContextWindowOptions, withContextWindowOptions } from "./context-window.js";
import { copilotApiBaseUrlFromToken, copilotTokenFromEnvironment, DEFAULT_COPILOT_API_BASE_URL, getActiveCopilotModelCatalog } from "./copilot-model-catalog.js";
import { copilotTemplateFromModels, copilotThinkingLevelMapFor, synthesizeCopilotCatalogModels } from "./copilot-model-synthesis.js";
import { getStaticCopilotModelFallback } from "./copilot-model-static-fallbacks.js";
const GITHUB_COPILOT_API_VERSION_HEADER = "X-GitHub-Api-Version";
const GITHUB_COPILOT_API_VERSION = "2026-06-01";
function withDynamicGitHubCopilotModels(provider, models) {
    if (provider !== "github-copilot")
        return models;
    const existingIds = new Set(models.map((model) => model.id));
    const template = copilotTemplateFromModels(models);
    const dynamicModels = synthesizeCopilotCatalogModels(getActiveCopilotModelCatalog(), existingIds, template);
    return dynamicModels.length === 0 ? models : [...models, ...dynamicModels];
}
function hasHeader(headers, headerName) {
    if (!headers)
        return false;
    const normalizedHeaderName = headerName.toLowerCase();
    return Object.keys(headers).some((key) => key.toLowerCase() === normalizedHeaderName);
}
export function withGitHubCopilotApiVersionHeader(model, headers) {
    if (model.provider !== "github-copilot" || hasHeader(headers, GITHUB_COPILOT_API_VERSION_HEADER)) {
        return headers;
    }
    return { ...(headers ?? {}), [GITHUB_COPILOT_API_VERSION_HEADER]: GITHUB_COPILOT_API_VERSION };
}
function withCopilotEnvironmentBaseUrl(model) {
    if (model.provider !== "github-copilot")
        return model;
    const resolvedBaseUrl = copilotApiBaseUrlFromToken(copilotTokenFromEnvironment());
    if (resolvedBaseUrl === DEFAULT_COPILOT_API_BASE_URL || resolvedBaseUrl === model.baseUrl)
        return model;
    return { ...model, baseUrl: resolvedBaseUrl };
}
function withCopilotThinkingLevelMap(model) {
    if (model.provider !== "github-copilot")
        return model;
    const context = getActiveCopilotModelCatalog().get(model.id);
    if (!context?.supports?.reasoningEffortLevels)
        return model;
    const thinkingLevelMap = copilotThinkingLevelMapFor(context, model.api);
    return thinkingLevelMap ? { ...model, thinkingLevelMap } : model;
}
function withCopilotContextWindowOptions(model) {
    if (model.provider !== "github-copilot")
        return model;
    // The live CAPI catalog (or its disk cache) is authoritative. Without an
    // entry (cold start, fetch failure, offline), fall back to the bundled
    // static CAPI snapshot: several bundled pi-ai definitions overstate the
    // enforced default-tier window or understate output caps, which lets
    // sessions sail past the server-side limits before compaction fires
    // (issue #1608). Fallback entries carry the same tier structure as catalog
    // entries so long-context (1M-class) tiers stay selectable offline.
    const context = getActiveCopilotModelCatalog().get(model.id) ?? getStaticCopilotModelFallback(model.id);
    if (!context)
        return model;
    const base = { ...model, contextWindow: context.contextWindow, maxInputTokens: context.maxInputTokens, maxTokens: context.maxTokens ?? model.maxTokens };
    if (context.contextWindowOptions && context.contextWindowOptions.length > 1) {
        return withContextWindowOptions(base, context.contextWindowOptions);
    }
    return base;
}
export function mergeCompat(baseCompat, overrideCompat) {
    if (!overrideCompat)
        return baseCompat;
    const base = baseCompat;
    const override = overrideCompat;
    const merged = { ...base, ...override };
    const baseCompletions = base;
    const overrideCompletions = override;
    const mergedCompletions = merged;
    if (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {
        mergedCompletions.openRouterRouting = {
            ...baseCompletions?.openRouterRouting,
            ...overrideCompletions.openRouterRouting,
        };
    }
    if (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {
        mergedCompletions.vercelGatewayRouting = {
            ...baseCompletions?.vercelGatewayRouting,
            ...overrideCompletions.vercelGatewayRouting,
        };
    }
    if (baseCompletions?.chatTemplateKwargs || overrideCompletions.chatTemplateKwargs) {
        mergedCompletions.chatTemplateKwargs = {
            ...baseCompletions?.chatTemplateKwargs,
            ...overrideCompletions.chatTemplateKwargs,
        };
    }
    return merged;
}
export function applyModelOverride(model, override) {
    const result = { ...model };
    if (override.name !== undefined)
        result.name = override.name;
    if (override.reasoning !== undefined)
        result.reasoning = override.reasoning;
    if (override.thinkingLevelMap !== undefined) {
        result.thinkingLevelMap = { ...model.thinkingLevelMap, ...override.thinkingLevelMap };
    }
    if (override.input !== undefined)
        result.input = override.input;
    if (override.contextWindow !== undefined) {
        result.contextWindow = override.contextWindow;
        result.defaultContextWindow = override.contextWindow;
        if (override.contextWindowOptions === undefined) {
            result.contextWindowOptions = undefined;
        }
    }
    if (override.contextWindowOptions !== undefined) {
        result.contextWindowOptions = normalizeContextWindowOptions(override.contextWindowOptions);
    }
    if (override.maxTokens !== undefined)
        result.maxTokens = override.maxTokens;
    if (override.cost) {
        result.cost = {
            input: override.cost.input ?? model.cost.input,
            output: override.cost.output ?? model.cost.output,
            cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,
            cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,
            ...(override.cost.tiers !== undefined
                ? { tiers: override.cost.tiers }
                : model.cost.tiers !== undefined
                    ? { tiers: model.cost.tiers }
                    : {}),
        };
    }
    result.compat = mergeCompat(model.compat, override.compat);
    return result;
}
export function loadBuiltInModels(overrides, modelOverrides) {
    return getProviders().flatMap((provider) => {
        const models = withDynamicGitHubCopilotModels(provider, getModels(provider));
        const providerOverride = overrides.get(provider);
        const perModelOverrides = modelOverrides.get(provider);
        return models.map((m) => {
            let model = withCopilotEnvironmentBaseUrl(m);
            if (providerOverride) {
                model = {
                    ...model,
                    baseUrl: providerOverride.baseUrl ?? model.baseUrl,
                    compat: mergeCompat(model.compat, providerOverride.compat),
                };
            }
            model = withCopilotThinkingLevelMap(withCopilotContextWindowOptions(model));
            const modelOverride = perModelOverrides?.get(m.id);
            return modelOverride ? applyModelOverride(model, modelOverride) : model;
        });
    });
}
export function mergeCustomModels(builtInModels, customModels) {
    const merged = [...builtInModels];
    for (const customModel of customModels) {
        const existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);
        if (existingIndex >= 0) {
            merged[existingIndex] = customModel;
        }
        else {
            merged.push(customModel);
        }
    }
    return merged;
}
//# sourceMappingURL=model-registry-builtins.js.map