import { homedir, platform } from "node:os";
import { join } from "node:path";
async function execOpen(ext, target, browser) {
    const os = platform();
    if (os === "darwin") {
        return browser ? ext.exec("open", ["-a", browser, target]) : ext.exec("open", [target]);
    }
    if (os === "win32") {
        return browser
            ? ext.exec("cmd", ["/c", "start", "", browser, target])
            : ext.exec("cmd", ["/c", "start", "", target]);
    }
    return browser ? ext.exec(browser, [target]) : ext.exec("xdg-open", [target]);
}
export async function openUrl(ext, url, browser) {
    const result = await execOpen(ext, url, browser);
    if (result.code !== 0) {
        throw new Error(result.stderr || `Failed to open browser (exit code ${result.code})`);
    }
}
export async function openPath(ext, targetPath) {
    const result = await execOpen(ext, targetPath);
    if (result.code !== 0) {
        throw new Error(result.stderr || `Failed to open path (exit code ${result.code})`);
    }
}
export async function parallelLimit(items, limit, fn) {
    const results = [];
    let index = 0;
    async function worker() {
        while (index < items.length) {
            const i = index++;
            results[i] = await fn(items[i]);
        }
    }
    const workers = Array(Math.min(limit, items.length)).fill(null).map(() => worker());
    await Promise.all(workers);
    return results;
}
export function getConfigPathFromArgv() {
    const idx = process.argv.indexOf("--mcp-config");
    if (idx >= 0 && idx + 1 < process.argv.length) {
        return process.argv[idx + 1];
    }
    return undefined;
}
export function interpolateEnvVars(value) {
    return value
        .replace(/\$\{(\w+)\}/g, (_, name) => process.env[name] ?? "")
        .replace(/\$env:(\w+)/g, (_, name) => process.env[name] ?? "");
}
export function interpolateEnvRecord(values) {
    if (!values)
        return undefined;
    const resolved = {};
    for (const [key, value] of Object.entries(values)) {
        resolved[key] = interpolateEnvVars(value);
    }
    return resolved;
}
export function resolveConfigPath(value) {
    if (value === undefined)
        return undefined;
    const resolved = interpolateEnvVars(value);
    if (resolved === "~")
        return homedir();
    if (resolved.startsWith("~/") || resolved.startsWith("~\\")) {
        return join(homedir(), resolved.slice(2));
    }
    return resolved;
}
export function resolveBearerToken(definition) {
    if (definition.bearerToken !== undefined) {
        return interpolateEnvVars(definition.bearerToken);
    }
    return definition.bearerTokenEnv ? process.env[definition.bearerTokenEnv] : undefined;
}
export function truncateAtWord(text, target) {
    if (!text || text.length <= target)
        return text;
    const truncated = text.slice(0, target);
    const lastSpace = truncated.lastIndexOf(" ");
    if (lastSpace > target * 0.6) {
        return truncated.slice(0, lastSpace) + "...";
    }
    return truncated + "...";
}
export function formatAuthRequiredMessage(config, serverName, defaultMessage) {
    const template = config.settings?.authRequiredMessage;
    return template ? template.replaceAll("${server}", serverName) : defaultMessage;
}
/**
 * Extract the adapter-owned UI stream mode from tool metadata.
 */
export function extractToolUiStreamMode(toolMeta) {
    const uiMeta = toolMeta?.ui;
    if (!uiMeta || typeof uiMeta !== "object")
        return undefined;
    const streamMode = uiMeta["spectral-mcp-adapter.streamMode"];
    if (streamMode === "eager" || streamMode === "stream-first") {
        return streamMode;
    }
    return undefined;
}
