/**
 * olam skills shadow-backups — manage A4's quarantine files.
 *
 *   olam skills shadow-backups list                       all backups + ages
 *   olam skills shadow-backups prune [--older-than=<dur>] delete old ones
 *                                    [--all --force]      OR delete every one
 *                                    [--dry-run]
 *   olam skills shadow-backups restore <path> [--force]   move back to original
 *
 * T2 mitigation: prevents unbounded backup growth without ever touching a
 * non-shadow-backup file (strict `.shadow-backup-<digits>` suffix match).
 */
import * as fs from 'node:fs';
import pc from 'picocolors';
import { listShadowBackups, pruneShadowBackups, restoreShadowBackup, parseDurationToMs, } from '@olam/core/src/skill-sources/index.js';
import { printError, printHeader, printSuccess } from '../output.js';
function asMessage(err) {
    return err instanceof Error ? err.message : String(err);
}
function formatAge(ms) {
    if (ms < 0)
        return '<future>';
    const d = Math.floor(ms / 86_400_000);
    if (d >= 1)
        return `${d}d`;
    const h = Math.floor(ms / 3_600_000);
    if (h >= 1)
        return `${h}h`;
    const m = Math.floor(ms / 60_000);
    if (m >= 1)
        return `${m}m`;
    const s = Math.floor(ms / 1_000);
    return `${s}s`;
}
function formatSize(bytes) {
    if (bytes < 1024)
        return `${bytes}B`;
    if (bytes < 1024 * 1024)
        return `${(bytes / 1024).toFixed(1)}KB`;
    return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
}
function printBackupRows(backups) {
    for (const b of backups) {
        const when = new Date(b.epochSeconds * 1000).toISOString().slice(0, 10);
        console.log(`  ${pc.dim(formatAge(b.ageMs).padStart(6))}  ${formatSize(b.sizeBytes).padStart(7)}  ${pc.dim(when)}  ${b.bucket}/${pc.bold(b.basename)}`);
    }
}
export function registerSkillsShadowBackups(program) {
    const skills = program.commands.find((c) => c.name() === 'skills') ??
        program.command('skills').description('Manage skill sources and synchronization');
    const sb = skills
        .command('shadow-backups')
        .description('Manage `.shadow-backup-<epoch>` quarantine files left by `olam skills sync`');
    sb.command('list')
        .description('List all shadow-backup files under ~/.claude/')
        .action(() => {
        const all = listShadowBackups();
        if (all.length === 0) {
            console.log(pc.dim('No shadow-backup files under ~/.claude/.'));
            return;
        }
        printHeader(`${all.length} shadow backup(s)`);
        console.log(pc.dim('   age      size  created     bucket/basename'));
        printBackupRows(all);
    });
    sb.command('prune')
        .description('Delete shadow-backup files older than a duration (e.g. 30d) OR all of them with --all --force')
        .option('--older-than <duration>', 'Delete backups older than this duration (e.g. 30d, 7d, 24h, 2w)', '30d')
        .option('--all', 'Delete every shadow-backup file (requires --force)')
        .option('--force', 'Confirm deletion when --all is used')
        .option('--dry-run', 'Show what would be deleted without deleting')
        .action((opts) => {
        try {
            let pruneOpts;
            if (opts.all === true) {
                if (opts.force !== true) {
                    printError('--all requires --force (refuses accidental wipes)');
                    process.exitCode = 1;
                    return;
                }
                pruneOpts = { all: true, dryRun: opts.dryRun };
            }
            else {
                const olderThanMs = parseDurationToMs(opts.olderThan);
                if (olderThanMs === undefined) {
                    printError(`unrecognized --older-than value "${opts.olderThan}" (expected like "30d", "7d", "24h", "2w")`);
                    process.exitCode = 1;
                    return;
                }
                pruneOpts = { olderThanMs, dryRun: opts.dryRun };
            }
            const result = pruneShadowBackups(pruneOpts);
            const action = opts.dryRun ? 'would delete' : 'deleted';
            if (result.deleted.length === 0) {
                console.log(pc.dim(`No shadow-backups match — ${result.skipped.length} kept`));
                return;
            }
            printHeader(`${action} ${result.deleted.length} shadow backup(s) (${result.skipped.length} kept)`);
            printBackupRows(result.deleted);
            if (opts.dryRun) {
                console.log(pc.dim('\n(dry-run — re-run without --dry-run to delete)'));
            }
            else {
                printSuccess(`pruned ${result.deleted.length} backup(s)`);
            }
        }
        catch (err) {
            printError(asMessage(err));
            process.exitCode = 1;
        }
    });
    sb.command('restore')
        .description('Move a shadow-backup file back to its original path')
        .argument('<path>', 'Absolute path to the .shadow-backup-<epoch> file')
        .option('--force', 'Overwrite the original path if it already exists')
        .action((p, opts) => {
        try {
            if (!fs.existsSync(p)) {
                printError(`backup file not found: ${p}`);
                process.exitCode = 1;
                return;
            }
            const result = restoreShadowBackup({ backupPath: p, force: opts.force });
            printSuccess(`restored → ${result.restoredTo}`);
        }
        catch (err) {
            printError(asMessage(err));
            process.exitCode = 1;
        }
    });
}
//# sourceMappingURL=skills-shadow-backups.js.map