/**
 * nexus uninstall — reverse every mutation Nexus Prime made to this machine.
 *
 * `--dry-run` walks registrations, processes, markers, and filesystem paths.
 * Default uninstall unregisters clients, stops processes, clears markers, removes
 * transient scratch, and clears the install manifest. `--purge` also deletes
 * durable state such as memory, Synapse, Architects, logs, caches, and worktrees.
 */
import * as fs from 'fs';
import * as readline from 'readline';
import { loadManifest, clearManifest } from '../install/manifest.js';
import { removeManifestRegistrations, removeHeuristicRegistrations } from '../install/registration.js';
import { stopAllNexusProcesses } from '../install/process-cleanup.js';
import { collectLeftovers, formatBytes, purgeStatePaths, purgeTmpRoots, } from '../install/fs-purge.js';
import { getNexusStateDir, getSetupMarkerPath, getInstallManifestPath, } from '../install/state-locator.js';
function prompt(question) {
    return new Promise((resolve) => {
        const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
        rl.question(question, (answer) => {
            rl.close();
            const a = answer.trim().toLowerCase();
            resolve(a === 'y' || a === 'yes');
        });
    });
}
function countPurgeOps(report) {
    let files = 0;
    let dirs = 0;
    let bytes = 0;
    for (const op of report.ops) {
        if (!op.removed && !report.dryRun)
            continue;
        if (op.kind === 'dir')
            dirs += 1;
        else if (op.kind === 'file')
            files += 1;
        bytes += op.bytes;
    }
    return { files, dirs, bytes };
}
export async function runUninstall(options) {
    const dryRun = options.dryRun;
    const purgeAll = options.purge ?? options.purgeAll ?? false;
    const workspaceRoot = options.workspaceRoot ?? process.cwd();
    const nexusStateDir = getNexusStateDir();
    const setupMarkerPath = getSetupMarkerPath();
    const installManifestPath = getInstallManifestPath();
    const report = {
        dryRun,
        purgeAll,
        daemonsKilled: 0,
        lockfilesRemoved: 0,
        registrationsRemoved: 0,
        filesRemoved: 0,
        dirsRemoved: 0,
        bytesReclaimed: 0,
        leftovers: [],
        errors: [],
        ok: false,
    };
    if (purgeAll && !dryRun && !options.yes && !options._forceYes) {
        console.log('\n⚠️  --purge will permanently delete Nexus Prime memory, workforce DBs, logs, and caches.');
        console.log(`   Target state dir: ${nexusStateDir}`);
        const confirmed = await prompt('   Proceed? [y/N] ');
        if (!confirmed) {
            console.log('   Aborted. No changes were made.');
            return report;
        }
    }
    const label = dryRun ? '[dry-run]' : '[uninstall]';
    console.log(`\n${label} Nexus Prime uninstall — workspace: ${workspaceRoot}`);
    const manifest = loadManifest();
    const unregisterReport = unregisterNexusRegistrations({ workspaceRoot, dryRun, manifest });
    const removedRegs = unregisterReport.reports.filter((r) => r.removed);
    report.registrationsRemoved = unregisterReport.registrationsRemoved;
    report.errors.push(...unregisterReport.errors);
    console.log(`  ${dryRun ? '◦' : '✓'} registrations: ${report.registrationsRemoved} cleared`);
    for (const r of removedRegs) {
        console.log(`      - ${r.filePath} :: ${r.jsonPath.join('.') || '(root)'}`);
    }
    const processReport = await stopAllNexusProcesses({ ...options._processCleanup, dryRun });
    report.daemonsKilled = processReport.daemonsKilled;
    report.lockfilesRemoved = processReport.lockfilesRemoved;
    report.errors.push(...processReport.errors);
    console.log(`  ${dryRun ? '◦' : '✓'} processes: ${report.daemonsKilled} process(es), ${report.lockfilesRemoved} lockfile(s)`);
    const markers = new Set([setupMarkerPath, ...manifest.setupMarkers]);
    for (const marker of markers) {
        if (!fs.existsSync(marker))
            continue;
        if (dryRun) {
            console.log(`  ◦ marker: would remove ${marker}`);
        }
        else {
            try {
                fs.unlinkSync(marker);
                console.log(`  ✓ marker: removed ${marker}`);
            }
            catch (err) {
                report.errors.push(`unlink ${marker}: ${err instanceof Error ? err.message : String(err)}`);
            }
        }
    }
    const extras = manifest.paths.map((e) => ({ path: e.path, scope: e.scope }));
    let stateReport = null;
    let tmpReport = null;
    if (purgeAll || dryRun) {
        stateReport = purgeStatePaths(extras, { dryRun });
        tmpReport = purgeTmpRoots({ dryRun });
    }
    else {
        tmpReport = purgeTmpRoots({ dryRun });
    }
    const totals = [stateReport, tmpReport]
        .filter((r) => r !== null)
        .map(countPurgeOps);
    for (const t of totals) {
        report.filesRemoved += t.files;
        report.dirsRemoved += t.dirs;
        report.bytesReclaimed += t.bytes;
    }
    console.log(`  ${dryRun ? '◦' : '✓'} filesystem: ${report.filesRemoved} file(s), ${report.dirsRemoved} dir(s), reclaimed ${formatBytes(report.bytesReclaimed)}`);
    if (purgeAll && stateReport) {
        for (const op of stateReport.ops) {
            if (!op.removed && !dryRun)
                continue;
            if (op.kind === 'missing')
                continue;
            console.log(`      - ${op.path}  (${formatBytes(op.bytes)})`);
        }
    }
    if (!dryRun) {
        clearManifest(installManifestPath);
    }
    report.leftovers = collectLeftovers(nexusStateDir);
    if (report.leftovers.length > 0) {
        console.log(`  ! leftovers (still present in state dir):`);
        for (const left of report.leftovers)
            console.log(`      - ${left}`);
    }
    if (report.errors.length > 0) {
        console.log(`  ! errors:`);
        for (const e of report.errors)
            console.log(`      - ${e}`);
    }
    report.ok = report.errors.length === 0 && (dryRun || (purgeAll ? report.leftovers.length === 0 : true));
    console.log(`\n${label} done. ${report.ok ? 'OK' : 'completed with issues'}.`);
    if (!purgeAll && !dryRun) {
        console.log('  Persistent memory preserved. All registrations, processes, manifest, and transient scratch were removed.');
        console.log('  Re-run with --purge --yes to delete durable memory/Synapse/Architects state too.');
    }
    return report;
}
export function unregisterNexusRegistrations(options = {}) {
    const workspaceRoot = options.workspaceRoot ?? process.cwd();
    const dryRun = options.dryRun ?? false;
    const manifest = options.manifest ?? loadManifest();
    const manifestRegs = removeManifestRegistrations(manifest, { dryRun });
    const heuristicRegs = removeHeuristicRegistrations(workspaceRoot, { dryRun });
    const reports = [...manifestRegs.reports, ...heuristicRegs.reports];
    return {
        registrationsRemoved: reports.filter((report) => report.removed).length,
        errors: reports
            .filter((report) => report.reason === 'unreadable')
            .map((report) => `unregister ${report.filePath}: unreadable`),
        reports,
    };
}
