/**
 * Nexus Prime — IDE Compatibility Utilities
 * Provides MCP config templates and detection logic for all supported IDEs.
 *
 * Supported: VS Code (Claude Code ext), JetBrains, Cursor, Windsurf, Zed, Continue.dev, Aider, Cline, Codex, and peer agent clients.
 */
import { existsSync } from 'fs';
import { homedir } from 'os';
import { dirname, join, resolve } from 'path';
import { buildNexusMcpServerConfig } from '../../engines/mcp-entrypoint.js';
let callerIDECache;
/** Nexus Prime MCP server entry (stdio transport). */
function nexusMcpServerEntry(workspaceRoot) {
    return buildNexusMcpServerConfig(workspaceRoot);
}
function hasAnyEnvPrefix(prefix) {
    return Object.keys(process.env).some((key) => key.startsWith(prefix));
}
function detectCallerIDEFromEnv() {
    if (process.env.CLAUDECODE || process.env.CLAUDE_CODE || process.env.CLAUDE_SESSION_ID || process.env.CLAUDE_PROJECT_DIR) {
        return 'claude-code';
    }
    if (process.env.CURSOR_TRACE_ID || hasAnyEnvPrefix('CURSOR_')) {
        return 'cursor';
    }
    if (process.env.CODEX_HOME || hasAnyEnvPrefix('CODEX_')) {
        return 'codex';
    }
    if (hasAnyEnvPrefix('WINDSURF_')) {
        return 'windsurf';
    }
    if (hasAnyEnvPrefix('OPENCLAW_') || hasAnyEnvPrefix('ANTIGRAVITY_')) {
        return 'openclaw';
    }
    if (hasAnyEnvPrefix('HERMES_')) {
        return 'hermes';
    }
    if (hasAnyEnvPrefix('NANOCLAW_')) {
        return 'nanoclaw';
    }
    if (hasAnyEnvPrefix('PICOCLAW_')) {
        return 'picoclaw';
    }
    if (hasAnyEnvPrefix('CONTINUE_')) {
        return 'continue';
    }
    if (hasAnyEnvPrefix('ZED_')) {
        return 'zed';
    }
    return null;
}
function detectCallerIDEFromFilesystem(startDir) {
    let current = resolve(startDir);
    for (;;) {
        if (existsSync(join(current, '.cursor')))
            return 'cursor';
        if (existsSync(join(current, '.continue')))
            return 'continue';
        if (existsSync(join(current, '.windsurf')))
            return 'windsurf';
        if (existsSync(join(current, '.openclaw')))
            return 'openclaw';
        if (existsSync(join(current, '.hermes')))
            return 'hermes';
        if (existsSync(join(current, '.nanoclaw')))
            return 'nanoclaw';
        if (existsSync(join(current, '.picoclaw')))
            return 'picoclaw';
        if (existsSync(join(current, '.zed')))
            return 'zed';
        const parent = dirname(current);
        if (parent === current) {
            return null;
        }
        current = parent;
    }
}
export function resetDetectedCallerIDECache() {
    callerIDECache = undefined;
}
export function detectCallerIDE() {
    if (callerIDECache !== undefined) {
        return callerIDECache;
    }
    callerIDECache = detectCallerIDEFromEnv() ?? detectCallerIDEFromFilesystem(process.cwd());
    return callerIDECache;
}
/** Detect which IDEs are present in the workspace or home directory. */
export function detectInstalledIDEs(workspaceRoot) {
    const detected = [];
    const home = homedir();
    // Claude Code: reads from ~/.claude/settings.json or project .claude/settings.json
    if (existsSync(join(home, '.claude')) ||
        existsSync(join(workspaceRoot, '.claude'))) {
        detected.push('claude-code');
    }
    // Cursor: .cursor/ directory in workspace or home
    if (existsSync(join(workspaceRoot, '.cursor')) ||
        existsSync(join(home, '.cursor'))) {
        detected.push('cursor');
    }
    // Windsurf: .windsurf/ directory
    if (existsSync(join(workspaceRoot, '.windsurf')) ||
        existsSync(join(home, '.windsurf'))) {
        detected.push('windsurf');
    }
    if (existsSync(join(workspaceRoot, '.openclaw')) ||
        existsSync(join(home, '.openclaw'))) {
        detected.push('openclaw');
    }
    if (existsSync(join(workspaceRoot, '.hermes')) ||
        existsSync(join(home, '.hermes'))) {
        detected.push('hermes');
    }
    if (existsSync(join(workspaceRoot, '.nanoclaw')) ||
        existsSync(join(home, '.nanoclaw'))) {
        detected.push('nanoclaw');
    }
    if (existsSync(join(workspaceRoot, '.picoclaw')) ||
        existsSync(join(home, '.picoclaw'))) {
        detected.push('picoclaw');
    }
    // Continue.dev: .continue/ directory
    if (existsSync(join(workspaceRoot, '.continue')) ||
        existsSync(join(home, '.continue'))) {
        detected.push('continue');
    }
    // Cline: VS Code extension — detected via .vscode/cline.json or cline settings
    if (existsSync(join(workspaceRoot, '.vscode', 'cline.json'))) {
        detected.push('cline');
    }
    // Zed: ~/.config/zed/
    if (existsSync(join(home, '.config', 'zed'))) {
        detected.push('zed');
    }
    // Codex: CODEX_HOME env or ~/.codex/
    if (process.env.CODEX_HOME || existsSync(join(home, '.codex'))) {
        detected.push('codex');
    }
    return detected;
}
/** Get the MCP config content and target path for a given IDE. */
export function getMcpConfigForIDE(ide, workspaceRoot) {
    const home = homedir();
    const entry = nexusMcpServerEntry(workspaceRoot);
    switch (ide) {
        case 'claude-code': {
            // Claude Code reads mcpServers from project .claude/settings.json
            const configPath = join(workspaceRoot, '.claude', 'settings.json');
            const content = JSON.stringify({
                mcpServers: {
                    'nexus-prime': entry,
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        case 'cursor': {
            // Cursor uses .cursor/mcp.json in the workspace
            const configPath = join(workspaceRoot, '.cursor', 'mcp.json');
            const content = JSON.stringify({
                mcpServers: {
                    'nexus-prime': entry,
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        case 'windsurf': {
            // Windsurf uses ~/.windsurf/mcp.json (global) or workspace .windsurf/mcp.json
            const configPath = existsSync(join(workspaceRoot, '.windsurf'))
                ? join(workspaceRoot, '.windsurf', 'mcp.json')
                : join(home, '.windsurf', 'mcp.json');
            const content = JSON.stringify({
                mcpServers: {
                    'nexus-prime': entry,
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        case 'openclaw':
        case 'hermes':
        case 'nanoclaw':
        case 'picoclaw': {
            const configPath = ide === 'openclaw'
                ? join(home, '.openclaw', 'openclaw.json')
                : join(home, `.${ide}`, 'mcp.json');
            const content = JSON.stringify({
                mcpServers: {
                    'nexus-prime': entry,
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        case 'continue': {
            // Continue.dev uses ~/.continue/config.json
            const configPath = join(home, '.continue', 'config.json');
            const content = JSON.stringify({
                mcpServers: {
                    'nexus-prime': entry,
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        case 'cline': {
            // Cline: .vscode/cline.json or global VS Code settings
            const configPath = join(workspaceRoot, '.vscode', 'cline.json');
            const content = JSON.stringify({
                mcpServers: {
                    'nexus-prime': entry,
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        case 'zed': {
            // Zed: ~/.config/zed/settings.json
            const configPath = join(home, '.config', 'zed', 'settings.json');
            const content = JSON.stringify({
                context_servers: {
                    'nexus-prime': {
                        command: entry.command,
                        args: entry.args,
                    },
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        case 'codex': {
            // Codex: ~/.codex/config.json or CODEX_HOME
            const codexHome = process.env.CODEX_HOME ?? join(home, '.codex');
            const configPath = join(codexHome, 'config.json');
            const content = JSON.stringify({
                mcpServers: {
                    'nexus-prime': entry,
                },
            }, null, 2);
            return { configPath, content, merge: true };
        }
        default:
            return { configPath: null, content: '{}', merge: false };
    }
}
/**
 * Normalise MCP tool response content for cross-client compatibility.
 * Some clients have subtle differences in how they render multi-part content.
 */
export function normalizeMcpContent(content) {
    return content
        .filter((c) => c.type === 'text' && c.text != null)
        .map((c) => ({ type: 'text', text: String(c.text ?? '') }));
}
