"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getProviders = getProviders;
exports.getProvider = getProvider;
exports.addProvider = addProvider;
exports.updateProvider = updateProvider;
exports.deleteProvider = deleteProvider;
exports.setProviders = setProviders;
exports.resolveProviderModel = resolveProviderModel;
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const uuid_1 = require("uuid");
const models_1 = require("../lib/models");
const paths_1 = require("../server/paths");
function prefsDir() {
    return (0, paths_1.getCockpitDir)();
}
function providersFile() {
    return (0, node_path_1.join)(prefsDir(), "providers.json");
}
function validateProvider(p) {
    for (const m of p.models) {
        if (!Array.isArray(m.contextSizes) || m.contextSizes.length === 0) {
            throw new Error(`provider${p.id ? ` ${p.id}` : ""}: model ${m.modelId} has empty contextSizes`);
        }
    }
}
function buildAnthropicProvider() {
    return {
        id: "anthropic",
        name: "Anthropic",
        envVars: {},
        models: (0, models_1.toProviderModels)(),
        isBuiltin: true,
    };
}
let cache = null;
// mtime of providers.json at the last load. Cockpit runs as two separate module
// graphs — the custom server (dist/, which spawns sessions) and the Next.js API
// routes (settings CRUD) — so a provider added/edited via settings only resets
// that graph's `cache`, never the spawner's, leaving new sessions on a stale list
// until restart. Gating the cache on the file mtime makes either graph (and a
// hand-edit of the file) reload when the file changes.
let cacheMtimeMs = 0;
function providersMtimeMs() {
    try {
        return (0, node_fs_1.statSync)(providersFile()).mtimeMs;
    }
    catch {
        return 0; // file absent — no custom providers yet
    }
}
function loadCustom() {
    try {
        return JSON.parse((0, node_fs_1.readFileSync)(providersFile(), "utf-8"));
    }
    catch {
        return [];
    }
}
function saveCustom(providers) {
    try {
        (0, node_fs_1.mkdirSync)(prefsDir(), { recursive: true });
        (0, node_fs_1.writeFileSync)(providersFile(), JSON.stringify(providers, null, 2) + "\n");
    }
    catch {
        // best effort
    }
}
function getProviders() {
    const mtime = providersMtimeMs();
    if (cache === null || mtime !== cacheMtimeMs) {
        cache = [buildAnthropicProvider(), ...loadCustom()];
        cacheMtimeMs = mtime;
    }
    return cache;
}
function getProvider(id) {
    return getProviders().find((p) => p.id === id);
}
function addProvider(provider) {
    const newProvider = { ...provider, id: (0, uuid_1.v4)() };
    validateProvider(newProvider);
    const all = getProviders();
    const custom = all.filter((p) => !p.isBuiltin);
    custom.push(newProvider);
    saveCustom(custom);
    cache = [buildAnthropicProvider(), ...custom];
    cacheMtimeMs = providersMtimeMs();
    return newProvider;
}
function updateProvider(id, partial) {
    if (id === "anthropic")
        throw new Error("Cannot modify built-in provider");
    const all = getProviders();
    const custom = all.filter((p) => !p.isBuiltin);
    const idx = custom.findIndex((p) => p.id === id);
    if (idx === -1)
        throw new Error(`Provider not found: ${id}`);
    const merged = { ...custom[idx], ...partial, id };
    validateProvider(merged);
    custom[idx] = merged;
    saveCustom(custom);
    cache = [buildAnthropicProvider(), ...custom];
    cacheMtimeMs = providersMtimeMs();
    return custom[idx];
}
function deleteProvider(id) {
    if (id === "anthropic")
        throw new Error("Cannot delete built-in provider");
    const all = getProviders();
    const custom = all.filter((p) => !p.isBuiltin && p.id !== id);
    if (custom.length === all.filter((p) => !p.isBuiltin).length) {
        throw new Error(`Provider not found: ${id}`);
    }
    saveCustom(custom);
    cache = [buildAnthropicProvider(), ...custom];
    cacheMtimeMs = providersMtimeMs();
}
function setProviders(providers) {
    const custom = providers.filter((p) => !p.isBuiltin);
    for (const p of custom)
        validateProvider(p);
    saveCustom(custom);
    cache = [buildAnthropicProvider(), ...custom];
    cacheMtimeMs = providersMtimeMs();
}
function resolveProviderModel(modelId) {
    if (!modelId)
        return null;
    const colon = modelId.indexOf(":");
    if (colon > 0) {
        const providerId = modelId.slice(0, colon);
        // Strip a legacy context suffix (e.g. "deepseek-v4-pro[1m]") so a job whose
        // stored model still carries one resolves to the cleaned provider model.
        const bareModel = modelId.slice(colon + 1).replace(/\[.*\]$/, "");
        const provider = getProvider(providerId);
        if (provider) {
            const model = provider.models.find((m) => m.modelId === bareModel);
            if (model)
                return { provider, model };
        }
        return null;
    }
    for (const provider of getProviders()) {
        const model = provider.models.find((m) => m.modelId === modelId);
        if (model)
            return { provider, model };
    }
    return null;
}
