import { randomUUID } from "node:crypto";
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
import { isRecord } from "./utils.js";
function isNonEmptyString(value) {
    return typeof value === "string" && value.length > 0;
}
function defaultCreateId() {
    return randomUUID();
}
function readJson(path) {
    if (!existsSync(path)) {
        return undefined;
    }
    return JSON.parse(readFileSync(path, "utf8"));
}
function writeAtomicJson(path, value) {
    const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
    try {
        writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8");
        renameSync(tmp, path);
    }
    catch (error) {
        try {
            if (existsSync(tmp)) {
                unlinkSync(tmp);
            }
        }
        catch {
            // best-effort cleanup
        }
        throw error;
    }
}
function getArrayRoot(root, key) {
    if (Array.isArray(root)) {
        return root;
    }
    if (!isRecord(root)) {
        return undefined;
    }
    const entries = root[key];
    return Array.isArray(entries) ? entries : undefined;
}
function ensureNamedResourceIds(path, key, options = {}) {
    const root = readJson(path);
    const entries = root === undefined ? undefined : getArrayRoot(root, key);
    const createId = options.createId ?? defaultCreateId;
    const resourceIdsByName = new Map();
    let changed = false;
    for (const entry of entries ?? []) {
        if (!isRecord(entry) || !isNonEmptyString(entry.name)) {
            continue;
        }
        if (!isNonEmptyString(entry.resourceId)) {
            entry.resourceId = createId();
            changed = true;
        }
        const resourceId = entry.resourceId;
        if (isNonEmptyString(resourceId)) {
            resourceIdsByName.set(entry.name, resourceId);
        }
    }
    if (changed && root !== undefined) {
        writeAtomicJson(path, root);
    }
    return { changed, resourceIdsByName };
}
export function ensureMcpResourceIds(path, options = {}) {
    return ensureNamedResourceIds(path, "servers", options);
}
export function ensureSourceResourceIds(path, options = {}) {
    return ensureNamedResourceIds(path, "sources", options);
}
export function ensureModelsResourceIds(path, options = {}) {
    const root = readJson(path);
    const createId = options.createId ?? defaultCreateId;
    const providerResourceIdsByName = new Map();
    const modelResourceIdsByProviderAndModel = new Map();
    let changed = false;
    if (isRecord(root) && isRecord(root.providers)) {
        for (const [providerName, provider] of Object.entries(root.providers)) {
            if (!isRecord(provider)) {
                continue;
            }
            if (!isNonEmptyString(provider.resourceId)) {
                provider.resourceId = createId();
                changed = true;
            }
            const providerResourceId = provider.resourceId;
            if (isNonEmptyString(providerResourceId)) {
                providerResourceIdsByName.set(providerName, providerResourceId);
            }
            if (!Array.isArray(provider.models)) {
                continue;
            }
            for (const model of provider.models) {
                if (!isRecord(model) || !isNonEmptyString(model.id)) {
                    continue;
                }
                if (!isNonEmptyString(model.resourceId)) {
                    model.resourceId = createId();
                    changed = true;
                }
                const modelResourceId = model.resourceId;
                if (isNonEmptyString(modelResourceId)) {
                    modelResourceIdsByProviderAndModel.set(`${providerName}:${model.id}`, modelResourceId);
                }
            }
        }
    }
    if (changed && root !== undefined) {
        writeAtomicJson(path, root);
    }
    return { changed, providerResourceIdsByName, modelResourceIdsByProviderAndModel };
}
//# sourceMappingURL=resource-ids.js.map