"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.showAgentsStatus = showAgentsStatus;
exports.getAgentsStatus = getAgentsStatus;
exports.installPlugin = installPlugin;
exports.updatePlugin = updatePlugin;
const node_fs_1 = require("node:fs");
const node_os_1 = __importDefault(require("node:os"));
const node_path_1 = require("node:path");
const node_child_process_1 = require("node:child_process");
const output_1 = require("../output");
const shellProbe_1 = require("../shellProbe");
const versionCompare_1 = require("../versionCompare");
const AGENTS = [
    { id: 'codex', name: 'Codex', cliCommand: 'codex', appNames: ['Codex', 'OpenAI Codex', 'ChatGPT'] },
    { id: 'claude', name: 'Claude', cliCommand: 'claude', appNames: ['Claude'] },
    { id: 'cursor', name: 'Cursor', cliCommand: 'cursor', appNames: ['Cursor'] },
];
const PUBLIC_PLUGIN_MANIFEST_URL = 'https://raw.githubusercontent.com/playdrop-ai/playdrop-plugin/main/.codex-plugin/plugin.json';
const PLAYDROP_PLUGIN_MARKETPLACE = 'playdrop-ai/playdrop-plugin';
const PLAYDROP_PLUGIN_SPEC = 'playdrop@playdrop';
async function showAgentsStatus(options = {}) {
    const status = await getAgentsStatus(options);
    if (options.json) {
        (0, output_1.printJson)(status);
    }
    else {
        printAgentsStatus(status);
    }
    return status;
}
async function getAgentsStatus(options = {}) {
    const homeDir = options.homeDir ?? node_os_1.default.homedir();
    const runShell = options.runShell ?? runLoginShell;
    const appExists = options.appExists ?? node_fs_1.existsSync;
    const latestPluginVersion = options.latestPluginVersion ?? await fetchLatestPublicPluginVersion();
    const agents = [];
    for (const agent of AGENTS) {
        const cli = await detectCli(agent.cliCommand, runShell);
        const app = detectApp(agent.appNames, homeDir, appExists);
        const plugin = await detectPlugin(agent.id, cli, runShell, latestPluginVersion);
        const account = await detectAccount(agent.id, runShell, homeDir);
        agents.push({
            id: agent.id,
            name: agent.name,
            app,
            cli,
            account,
            plugin,
            nextAction: buildNextAction(agent.id, plugin),
        });
    }
    return { agents };
}
async function installPlugin(agentID, options = {}) {
    await runPluginAction('install-plugin', agentID, options);
}
async function updatePlugin(agentID, options = {}) {
    await runPluginAction('update-plugin', agentID, options);
}
async function runPluginAction(action, rawAgentID, options) {
    const agentID = normalizeAgentID(rawAgentID);
    if (!agentID) {
        console.error(`Unknown agent "${rawAgentID}". Expected codex, claude, or cursor.`);
        process.exitCode = 1;
        return;
    }
    const runCommand = options.runCommand ?? runCommandSync;
    if (agentID === 'codex') {
        runCodexPluginAction(action, runCommand);
        return;
    }
    if (agentID === 'claude') {
        runClaudePluginAction(action, runCommand);
        return;
    }
    printCursorManualInstall();
    process.exitCode = 1;
}
function normalizeAgentID(value) {
    return value === 'codex' || value === 'claude' || value === 'cursor' ? value : null;
}
async function detectCli(command, runShell) {
    const pathProbe = await runShell((0, shellProbe_1.buildCommandPathProbe)(command));
    if (pathProbe.exitCode !== 0 || pathProbe.output.trim().length === 0) {
        return { installed: false };
    }
    const versionProbe = await runShell(`${command} --version`);
    return {
        installed: true,
        path: pathProbe.output.split('\n')[0]?.trim(),
        version: versionProbe.exitCode === 0 ? versionProbe.output.split('\n')[0]?.trim() : undefined,
    };
}
function detectApp(appNames, homeDir, appExists) {
    for (const root of ['/Applications', (0, node_path_1.join)(homeDir, 'Applications')]) {
        for (const appName of appNames) {
            const candidate = (0, node_path_1.join)(root, `${appName}.app`);
            if (appExists(candidate)) {
                return { installed: true, path: candidate };
            }
        }
    }
    return { installed: false };
}
async function detectPlugin(agentID, cli, runShell, latestVersion) {
    if (agentID === 'cursor') {
        return {
            installed: false,
            status: 'manual-verification-required',
            latestVersion,
            updateAvailable: false,
            installableFromCli: false,
            message: 'Cursor CLI cannot verify plugin installation. Open Cursor and use /add-plugin or the Cursor Marketplace.',
        };
    }
    if (!cli.installed) {
        return {
            installed: false,
            status: 'unknown',
            latestVersion,
            updateAvailable: false,
            installableFromCli: true,
            message: `${agentID === 'codex' ? 'Codex' : 'Claude'} CLI is missing, so installed plugins cannot be checked.`,
        };
    }
    const list = await runShell(`${agentID} plugin list --json 2>&1`);
    if (list.exitCode !== 0) {
        return {
            installed: false,
            status: agentID === 'codex' ? 'manual-verification-required' : 'unknown',
            latestVersion,
            updateAvailable: false,
            installableFromCli: true,
            message: agentID === 'codex'
                ? 'Codex CLI cannot verify installed plugins. Open Codex and run /plugins to install, enable, or verify PlayDrop.'
                : 'Could not read Claude installed plugins through claude plugin list --json.',
        };
    }
    const plugin = selectPlayDropPlugin(parseInstalledPlugins(list.output));
    if (!plugin) {
        return {
            installed: false,
            status: 'missing',
            latestVersion,
            updateAvailable: false,
            installableFromCli: true,
        };
    }
    const version = typeof plugin.version === 'string' && plugin.version.trim() ? plugin.version.trim() : undefined;
    const enabled = typeof plugin.enabled === 'boolean' ? plugin.enabled : undefined;
    return {
        installed: true,
        status: enabled === false ? 'activation-required' : 'installed',
        id: normalizePluginID(plugin),
        path: typeof plugin.installPath === 'string' ? plugin.installPath : plugin.path,
        version,
        latestVersion,
        updateAvailable: (0, versionCompare_1.firstVersionIsNewer)(latestVersion, version),
        enabled,
        scope: typeof plugin.scope === 'string' ? plugin.scope : undefined,
        installableFromCli: true,
    };
}
async function fetchLatestPublicPluginVersion() {
    try {
        const response = await fetch(PUBLIC_PLUGIN_MANIFEST_URL, { headers: { Accept: 'application/json' } });
        if (!response.ok) {
            return undefined;
        }
        const parsed = await response.json();
        return typeof parsed.version === 'string' && parsed.version.trim().length > 0 ? parsed.version.trim() : undefined;
    }
    catch {
        return undefined;
    }
}
async function detectAccount(agentID, runShell, homeDir) {
    if (agentID === 'codex') {
        return readCodexAuthAccount(homeDir);
    }
    if (agentID === 'claude') {
        const result = await runShell('claude auth status 2>&1');
        if (result.exitCode !== 0 || !result.output.trim()) {
            return { signedIn: null };
        }
        try {
            const parsed = JSON.parse(result.output);
            if (!parsed.loggedIn) {
                return { signedIn: false };
            }
            return {
                identity: parsed.email || parsed.authMethod || 'Signed in',
                subscription: parsed.subscriptionType,
                signedIn: true,
            };
        }
        catch {
            return { identity: result.output.split('\n')[0]?.trim(), signedIn: null };
        }
    }
    return { signedIn: null };
}
function readCodexAuthAccount(homeDir) {
    try {
        const parsed = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(homeDir, '.codex', 'auth.json'), 'utf8'));
        const tokens = parsed.tokens;
        if (tokens && typeof tokens.id_token === 'string') {
            const payload = decodeJWTPayload(tokens.id_token);
            const email = typeof payload?.email === 'string' ? payload.email : undefined;
            const plan = payload?.['https://api.openai.com/auth']?.chatgpt_plan_type;
            if (email) {
                return {
                    identity: email,
                    subscription: typeof plan === 'string' && plan ? plan : undefined,
                    signedIn: true,
                };
            }
        }
        if (typeof parsed.auth_mode === 'string') {
            return {
                identity: parsed.auth_mode === 'apikey' ? 'API key' : parsed.auth_mode,
                signedIn: true,
            };
        }
    }
    catch {
        return { signedIn: false };
    }
    return { signedIn: false };
}
function decodeJWTPayload(token) {
    const parts = token.split('.');
    const payload = parts[1];
    if (!payload) {
        return null;
    }
    const padded = payload.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - payload.length % 4) % 4);
    try {
        return JSON.parse(Buffer.from(padded, 'base64').toString('utf8'));
    }
    catch {
        return null;
    }
}
function buildNextAction(agentID, plugin) {
    if (plugin.status === 'manual-verification-required') {
        return null;
    }
    if (plugin.status === 'unknown') {
        return null;
    }
    if (!plugin.installed) {
        return { command: `playdrop agents install-plugin ${agentID}`, reason: 'PlayDrop plugin is not installed.' };
    }
    if (plugin.status === 'activation-required' || plugin.enabled === false) {
        const command = agentID === 'claude' && plugin.id ? `claude plugin enable ${plugin.id}` : `playdrop agents install-plugin ${agentID}`;
        return { command, reason: 'PlayDrop plugin is installed but disabled.' };
    }
    if (plugin.updateAvailable) {
        return { command: `playdrop agents update-plugin ${agentID}`, reason: 'PlayDrop plugin update is available.' };
    }
    return null;
}
function printAgentsStatus(status) {
    for (const agent of status.agents) {
        console.log(agent.name);
        console.log(`  CLI: ${agent.cli.installed ? agent.cli.version ?? agent.cli.path ?? 'installed' : 'missing'}`);
        console.log(`  App: ${agent.app.installed ? agent.app.path ?? 'installed' : 'missing'}`);
        const account = agent.account?.identity
            ? agent.account.subscription
                ? `${agent.account.identity} (${agent.account.subscription})`
                : agent.account.identity
            : agent.account?.signedIn === false
                ? 'not signed in'
                : 'unknown';
        console.log(`  Account: ${account}`);
        console.log(`  PlayDrop plugin: ${formatPluginForAgentsStatus(agent.plugin)}`);
        if (agent.nextAction) {
            console.log(`  Run: ${agent.nextAction.command}`);
        }
    }
}
function runCodexPluginAction(action, runCommand) {
    const marketplaceCommand = action === 'install-plugin'
        ? ['plugin', 'marketplace', 'add', PLAYDROP_PLUGIN_MARKETPLACE]
        : ['plugin', 'marketplace', 'upgrade', 'playdrop'];
    const marketplace = runCommand('codex', marketplaceCommand);
    if (marketplace.status !== 0) {
        console.error(`Codex PlayDrop plugin ${action} failed.`);
        process.exitCode = 1;
        return;
    }
    const help = runCommand('codex', ['plugin', '--help']);
    const helpText = commandOutput(help);
    if (action === 'install-plugin' && commandHelpIncludes(helpText, 'install')) {
        const install = runCommand('codex', ['plugin', 'install', PLAYDROP_PLUGIN_SPEC]);
        if (install.status !== 0) {
            console.error('Codex PlayDrop plugin install failed.');
            process.exitCode = 1;
            return;
        }
        if (commandHelpIncludes(helpText, 'list') && !readInstalledPlayDropPlugin('codex', runCommand)) {
            console.error('Codex PlayDrop plugin install could not be verified from codex plugin list --json.');
            process.exitCode = 1;
            return;
        }
        console.log('Installed the PlayDrop plugin for Codex.');
        return;
    }
    if (action === 'update-plugin' && commandHelpIncludes(helpText, 'update')) {
        const update = runCommand('codex', ['plugin', 'update', PLAYDROP_PLUGIN_SPEC]);
        if (update.status !== 0) {
            console.error('Codex PlayDrop plugin update failed.');
            process.exitCode = 1;
            return;
        }
        console.log('Updated the PlayDrop plugin for Codex.');
        return;
    }
    console.log('Codex PlayDrop plugin marketplace is configured.');
    console.log('Open Codex and run /plugins, then install or enable PlayDrop.');
}
function runClaudePluginAction(action, runCommand) {
    if (action === 'install-plugin') {
        const marketplace = runCommand('claude', ['plugin', 'marketplace', 'add', PLAYDROP_PLUGIN_MARKETPLACE]);
        if (marketplace.status !== 0) {
            console.error('Claude PlayDrop marketplace install failed.');
            process.exitCode = 1;
            return;
        }
        const install = runCommand('claude', ['plugin', 'install', PLAYDROP_PLUGIN_SPEC]);
        if (install.status !== 0) {
            console.error('Claude PlayDrop plugin install failed.');
            process.exitCode = 1;
            return;
        }
        if (!readInstalledPlayDropPlugin('claude', runCommand)) {
            console.error('Claude PlayDrop plugin install could not be verified from claude plugin list --json.');
            process.exitCode = 1;
            return;
        }
        console.log('Installed the PlayDrop plugin for Claude.');
        console.log('Run /reload-plugins in Claude Code or restart Claude Code to apply it.');
        return;
    }
    const installed = readInstalledPlayDropPlugin('claude', runCommand);
    if (!installed) {
        console.error('PlayDrop plugin is not installed for Claude.');
        console.error('Run "playdrop agents install-plugin claude" first.');
        process.exitCode = 1;
        return;
    }
    const updateTarget = normalizePluginID(installed) ?? 'playdrop';
    const update = runCommand('claude', ['plugin', 'update', updateTarget]);
    if (update.status !== 0) {
        console.error('Claude PlayDrop plugin update failed.');
        process.exitCode = 1;
        return;
    }
    console.log('Updated the PlayDrop plugin for Claude.');
    console.log('Run /reload-plugins in Claude Code or restart Claude Code to apply it.');
}
function readInstalledPlayDropPlugin(command, runCommand) {
    const list = runCommand(command, ['plugin', 'list', '--json']);
    if (list.status !== 0) {
        return null;
    }
    return selectPlayDropPlugin(parseInstalledPlugins(list.stdout ?? ''));
}
function parseInstalledPlugins(output) {
    try {
        const parsed = JSON.parse(output);
        if (Array.isArray(parsed)) {
            return parsed.filter(isInstalledPluginRecord);
        }
        if (isRecord(parsed)) {
            for (const key of ['plugins', 'installed', 'items']) {
                const value = parsed[key];
                if (Array.isArray(value)) {
                    return value.filter(isInstalledPluginRecord);
                }
            }
        }
    }
    catch {
        return [];
    }
    return [];
}
function selectPlayDropPlugin(plugins) {
    const candidates = plugins.filter((plugin) => isPlayDropPluginID(normalizePluginID(plugin)));
    if (candidates.length === 0) {
        return null;
    }
    return candidates.sort((left, right) => pluginPriority(right) - pluginPriority(left))[0] ?? null;
}
function isInstalledPluginRecord(value) {
    return isRecord(value);
}
function normalizePluginID(plugin) {
    if (typeof plugin.id === 'string' && plugin.id.trim()) {
        return plugin.id.trim();
    }
    if (typeof plugin.name === 'string' && plugin.name.trim()) {
        return plugin.name.trim();
    }
    return undefined;
}
function isPlayDropPluginID(id) {
    if (!id) {
        return false;
    }
    return id === 'playdrop' || id.startsWith('playdrop@');
}
function pluginPriority(plugin) {
    const id = normalizePluginID(plugin);
    if (id === PLAYDROP_PLUGIN_SPEC) {
        return 3;
    }
    if (id === 'playdrop') {
        return 2;
    }
    return isPlayDropPluginID(id) ? 1 : 0;
}
function commandHelpIncludes(helpText, command) {
    return new RegExp(`(^|\\n)\\s*${command}(\\s|$)`).test(helpText);
}
function commandOutput(result) {
    return [result.stdout, result.stderr].filter(Boolean).join('\n');
}
function printCursorManualInstall() {
    console.error('Cursor does not expose plugin installation through its CLI.');
    console.error('Open Cursor and use /add-plugin or the Cursor Marketplace to install PlayDrop.');
    console.error('Plugin source: https://github.com/playdrop-ai/playdrop-plugin');
}
function formatPluginForAgentsStatus(plugin) {
    if (plugin.status === 'manual-verification-required') {
        return plugin.latestVersion ? `manual verification required, latest: ${plugin.latestVersion}` : 'manual verification required';
    }
    if (plugin.status === 'unknown') {
        return plugin.message ? `unknown (${plugin.message})` : 'unknown';
    }
    if (!plugin.installed) {
        return plugin.latestVersion ? `missing, latest: ${plugin.latestVersion}` : 'missing';
    }
    const installedVersion = plugin.version ?? 'installed';
    const enabled = plugin.status === 'activation-required' || plugin.enabled === false ? ', activation required' : '';
    if (plugin.updateAvailable) {
        return `${installedVersion}${enabled}, update available: ${plugin.latestVersion ?? 'unknown'}`;
    }
    return `${installedVersion}${enabled}, up to date`;
}
function isRecord(value) {
    return typeof value === 'object' && value !== null;
}
async function runLoginShell(command) {
    return (0, shellProbe_1.runShell)(command);
}
function runCommandSync(command, args) {
    const result = (0, node_child_process_1.spawnSync)(command, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
    return {
        status: result.status,
        stdout: result.stdout ?? '',
        stderr: result.stderr ?? '',
    };
}
