/**
 * `agents secrets push|pull` subcommands.
 *
 * Replaces iCloud Keychain as the cross-device sync mechanism with explicit
 * encrypted-at-rest sync against api.prix.dev. Plaintext never leaves the
 * machine — bundle contents are sealed with AES-256-GCM under a user-supplied
 * passphrase before upload.
 */
import chalk from 'chalk';
import { listRemoteBundles, MIN_PASSPHRASE_LEN, pullBundle, pushBundle, } from '../lib/secrets/sync.js';
import { bundleExists, listBundles } from '../lib/secrets/bundles.js';
import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
import { missingSyncPassphraseMessage, resolveSyncPassphraseFromEnv, warnEnvPassphraseReadableOnce, } from '../lib/secrets/sync-passphrase.js';
async function promptPassphrase(message, confirm = false) {
    if (!isInteractiveTerminal()) {
        throw new Error(missingSyncPassphraseMessage());
    }
    const { password } = await import('@inquirer/prompts');
    const first = await password({ message, mask: true });
    if (first.length < MIN_PASSPHRASE_LEN)
        throw new Error(`Passphrase must be at least ${MIN_PASSPHRASE_LEN} characters.`);
    if (!confirm)
        return first;
    const second = await password({ message: 'Confirm passphrase', mask: true });
    if (first !== second)
        throw new Error('Passphrases do not match.');
    return first;
}
function passphraseFromEnvOrPrompt(confirm) {
    // Env resolution (current name, then the deprecated master-key name) lives in
    // lib/secrets/sync-passphrase.ts so this command and `agents sync` share one
    // chokepoint — otherwise each call site warns separately and the "once per
    // process" promise is a lie.
    const { value } = resolveSyncPassphraseFromEnv();
    if (value) {
        if (value.length < MIN_PASSPHRASE_LEN) {
            return Promise.reject(new Error(`Passphrase must be at least ${MIN_PASSPHRASE_LEN} characters.`));
        }
        warnEnvPassphraseReadableOnce();
        return Promise.resolve(value);
    }
    return promptPassphrase('Sync passphrase', confirm);
}
/** Strip C0/C1 control bytes from server-supplied strings before terminal print. */
function safePrint(s) {
    return s.replace(/[\x00-\x08\x0B-\x1F\x7F-\x9F]/g, '');
}
/** Register `agents secrets push|pull|remote-list` on the parent secrets Command. */
export function registerSecretsSyncCommands(secrets) {
    secrets
        .command('push [name]')
        .description('Encrypt a local bundle and upload it to api.prix.dev (replaces iCloud Keychain sync).')
        .option('--all', 'Push every local bundle (each prompts independently if no passphrase env var is set)')
        .action(async (name, opts) => {
        try {
            if (opts.all) {
                const bundles = listBundles();
                if (bundles.length === 0) {
                    console.log(chalk.gray('No local bundles to push.'));
                    return;
                }
                const passphrase = await passphraseFromEnvOrPrompt(true);
                for (const b of bundles) {
                    try {
                        const { updated_at } = await pushBundle(b.name, { passphrase });
                        console.log(chalk.green(`Pushed '${b.name}' (updated_at=${updated_at}).`));
                    }
                    catch (err) {
                        console.error(chalk.red(`Failed to push '${b.name}': ${err.message}`));
                    }
                }
                return;
            }
            if (!name) {
                throw new Error('Bundle name required. Try: agents secrets push <name> | agents secrets push --all');
            }
            if (!bundleExists(name)) {
                throw new Error(`Bundle '${name}' not found locally.`);
            }
            const passphrase = await passphraseFromEnvOrPrompt(true);
            const { updated_at } = await pushBundle(name, { passphrase });
            console.log(chalk.green(`Pushed '${name}' to api.prix.dev (updated_at=${updated_at}).`));
            console.log(chalk.gray('Remember the passphrase — it is required to pull this bundle on another machine.'));
        }
        catch (err) {
            if (isPromptCancelled(err))
                return;
            console.error(chalk.red(err.message));
            process.exit(1);
        }
    });
    secrets
        .command('pull [name]')
        .description('Decrypt a remote bundle from api.prix.dev and restore it into the local keychain.')
        .option('--all', 'Pull every bundle visible on the remote')
        .option('--force', 'Overwrite a local bundle with the same name')
        .action(async (name, opts) => {
        try {
            if (opts.all) {
                const remote = await listRemoteBundles();
                if (remote.length === 0) {
                    console.log(chalk.gray('No remote bundles found.'));
                    return;
                }
                const passphrase = await passphraseFromEnvOrPrompt(false);
                for (const r of remote) {
                    try {
                        await pullBundle(r.name, { passphrase, force: opts.force });
                        console.log(chalk.green(`Pulled '${r.name}'.`));
                    }
                    catch (err) {
                        console.error(chalk.red(`Failed to pull '${r.name}': ${err.message}`));
                    }
                }
                return;
            }
            if (!name) {
                throw new Error('Bundle name required. Try: agents secrets pull <name> | agents secrets pull --all');
            }
            const passphrase = await passphraseFromEnvOrPrompt(false);
            const bundle = await pullBundle(name, { passphrase, force: opts.force });
            const keyCount = Object.keys(bundle.vars).length;
            console.log(chalk.green(`Pulled '${name}' (${keyCount} key${keyCount === 1 ? '' : 's'}) into local keychain.`));
        }
        catch (err) {
            if (isPromptCancelled(err))
                return;
            console.error(chalk.red(err.message));
            process.exit(1);
        }
    });
    secrets
        .command('remote-list')
        .alias('remote-ls')
        .description('List bundles currently stored on api.prix.dev for this account.')
        .action(async () => {
        try {
            const remote = await listRemoteBundles();
            if (remote.length === 0) {
                console.log(chalk.gray('No remote bundles found.'));
                return;
            }
            console.log(chalk.bold(`${'NAME'.padEnd(24)} UPDATED_AT`));
            for (const r of remote) {
                console.log(`${chalk.cyan(safePrint(r.name).padEnd(24))} ${chalk.gray(safePrint(r.updated_at))}`);
            }
        }
        catch (err) {
            console.error(chalk.red(err.message));
            process.exit(1);
        }
    });
}
