// engine/mcp-config/mcp-config-writer.ts — SPEC-756
// Detects the MCP config file for the client project and injects a direct Planu entry
// so the client is no longer dependent on a bundled (possibly outdated) version.
import { readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { homedir } from 'node:os';
import { buildNpxLatestEntry } from '../auto-updater/config-patcher.js';
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const PLANU_KEY = 'planu';
const PLANU_LATEST_ARG = '@planu/cli@latest';
const MIN_STARTUP_TIMEOUT_SEC = 60;
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
async function readJsonFile(filePath) {
    try {
        const raw = await readFile(filePath, 'utf-8');
        const parsed = JSON.parse(raw);
        if (typeof parsed === 'object' && parsed !== null) {
            return parsed;
        }
        return {};
    }
    catch {
        return {};
    }
}
async function fileExists(filePath) {
    try {
        await readFile(filePath, 'utf-8');
        return true;
    }
    catch {
        return false;
    }
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Finds (or creates) the MCP config file for a project.
 * Search order:
 *   1. <projectPath>/.mcp.json
 *   2. ~/.claude/claude.json
 *   3. <projectPath>/.claude.json
 * If none exist, returns the path for .mcp.json (caller writes it).
 */
export async function findMcpConfigPath(projectPath) {
    const candidates = [
        join(projectPath, '.mcp.json'),
        join(homedir(), '.claude', 'claude.json'),
        join(projectPath, '.claude.json'),
    ];
    for (const candidate of candidates) {
        if (await fileExists(candidate)) {
            return candidate;
        }
    }
    // None exist — return the default creation path
    return join(projectPath, '.mcp.json');
}
/**
 * Returns true if the config already has a safe `planu` entry pointing to @planu/cli@latest.
 */
export async function isPlanuDirectlyConfigured(configPath) {
    const config = await readJsonFile(configPath);
    const servers = config.mcpServers;
    if (servers === undefined) {
        return false;
    }
    const planuEntry = servers[PLANU_KEY];
    if (planuEntry === undefined) {
        return false;
    }
    const args = planuEntry.args;
    if (!Array.isArray(args)) {
        return false;
    }
    return (args.includes(PLANU_LATEST_ARG) &&
        (planuEntry.startup_timeout_sec ?? 0) >= MIN_STARTUP_TIMEOUT_SEC);
}
/**
 * Merges the direct Planu entry into the config file.
 * Does not overwrite unrelated keys.
 */
export async function injectDirectPlanuEntry(configPath, currentVersion, latestVersion) {
    const existing = await readJsonFile(configPath);
    const mcpServers = existing.mcpServers !== undefined ? { ...existing.mcpServers } : {};
    mcpServers[PLANU_KEY] = buildNpxLatestEntry();
    const updated = {
        ...existing,
        mcpServers,
        _planuAutoConfigured: {
            at: new Date().toISOString(),
            from: currentVersion,
            to: latestVersion,
            reason: 'SPEC-756: bundled version gap detected',
        },
    };
    await writeFile(configPath, JSON.stringify(updated, null, 2) + '\n', 'utf-8');
}
// ---------------------------------------------------------------------------
// High-level orchestrator
// ---------------------------------------------------------------------------
/**
 * Checks if a version gap exists and, if so, injects the direct Planu MCP entry.
 * Returns a structured result for the tool response.
 */
export async function checkAndFixBundledVersion(projectPath, currentVersion, latestVersion) {
    const configPath = await findMcpConfigPath(projectPath);
    const alreadyConfigured = await isPlanuDirectlyConfigured(configPath);
    if (alreadyConfigured) {
        return { configured: false, reason: 'already configured with @planu/cli@latest' };
    }
    await injectDirectPlanuEntry(configPath, currentVersion, latestVersion);
    /* c8 ignore next — `?? configPath` fallback is unreachable (split always produces at least one element) */
    const configFile = configPath.split('/').pop() ?? configPath;
    const message = `⚡ Planu detected bundled version (v${currentVersion} → v${latestVersion} available). Direct MCP entry added to ${configFile} — restart Claude Code to get the latest version.`;
    return {
        configured: true,
        configPath,
        currentVersion,
        latestVersion,
        message,
    };
}
//# sourceMappingURL=mcp-config-writer.js.map