/**
 * `olam skills migrate-back-to-toolbox` — reverse the migration performed
 * by `migrate-from-toolbox`, consuming the pre-migration snapshot written
 * at ~/.olam/state/migration-snapshots/<namespace>-<ISO>.json.
 *
 * Reverse order of migrate-from-toolbox operations:
 *   1. resolve snapshot (latest matching --path / --namespace / --snapshot)
 *   2. uninstall olam-skills SessionStart hook (sentinel-matched)
 *   3. delete olam-managed symlinks under ~/.claude/ (any symlink whose
 *      target lives under ~/.olam/state/skill-sources/<id>/)
 *   4. restore the original SessionStart hook block from snapshot
 *   5. restore the toolbox-managed symlinks from snapshot
 *   6. restore ~/.claude/.atlas-user from snapshot (atlas-shape only)
 *   7. unless --keep-source: remove the toolbox olam source registration
 *      (skill-sources slice + clone dir)
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import { readLatestMigrationSnapshot, readMigrationSnapshotFromPath, uninstallSkillsHookFromFile, claudeSettingsPath, listSkillSources, removeSkillSource, removeSkillSourceClone, skillSourceClonePath, } from '@olam/core/src/skill-sources/index.js';
import { printError, printInfo, printSuccess, printWarning } from '../output.js';
/** Stable command identifier — referenced by tests to keep them rename-resilient. */
export const MIGRATE_BACK_TO_TOOLBOX_COMMAND = 'migrate-back-to-toolbox';
function asMessage(err) {
    return err instanceof Error ? err.message : String(err);
}
function claudeDirInternal() {
    const override = process.env['OLAM_CLAUDE_DIR'];
    if (override && override.length > 0)
        return override;
    return path.join(process.env['HOME'] ?? '', '.claude');
}
function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
    if (!originalSessionStartHook || originalSessionStartHook.length === 0) {
        return { restored: false };
    }
    let settings;
    if (fs.existsSync(filePath)) {
        try {
            const raw = fs.readFileSync(filePath, 'utf-8');
            settings = raw.trim() ? JSON.parse(raw) : {};
        }
        catch {
            settings = {};
        }
    }
    else {
        settings = {};
    }
    // Replace SessionStart entirely with snapshot's array (we uninstalled olam
    // entries already; this restores the original state byte-for-byte).
    const hooks = (settings.hooks && typeof settings.hooks === 'object') ? settings.hooks : {};
    const next = {
        ...settings,
        hooks: {
            ...hooks,
            SessionStart: originalSessionStartHook,
        },
    };
    fs.mkdirSync(path.dirname(filePath), { recursive: true });
    fs.writeFileSync(filePath, JSON.stringify(next, null, 2) + '\n');
    return { restored: true };
}
function removeOlamManagedSymlinks() {
    const claude = claudeDirInternal();
    const sources = listSkillSources();
    const olamClonePaths = sources.map((s) => skillSourceClonePath(s.id));
    let removed = 0;
    for (const bucket of ['skills', 'agents', 'scripts', 'rules', 'commands']) {
        const dir = path.join(claude, bucket);
        if (!fs.existsSync(dir))
            continue;
        for (const name of fs.readdirSync(dir)) {
            const linkPath = path.join(dir, name);
            try {
                const stat = fs.lstatSync(linkPath);
                if (!stat.isSymbolicLink())
                    continue;
                const target = fs.readlinkSync(linkPath);
                if (olamClonePaths.some((cp) => target.startsWith(cp))) {
                    fs.unlinkSync(linkPath);
                    removed += 1;
                }
            }
            catch {
                // best-effort
            }
        }
    }
    return removed;
}
function restoreToolboxSymlinks(symlinks) {
    let restored = 0;
    for (const { link, target } of symlinks) {
        try {
            fs.mkdirSync(path.dirname(link), { recursive: true });
            if (fs.existsSync(link) || (() => { try {
                fs.lstatSync(link);
                return true;
            }
            catch {
                return false;
            } })()) {
                fs.unlinkSync(link);
            }
            fs.symlinkSync(target, link);
            restored += 1;
        }
        catch {
            // best-effort
        }
    }
    return restored;
}
function restoreAtlasUserMarker(atlasUser) {
    if (!atlasUser)
        return false;
    const file = path.join(claudeDirInternal(), '.atlas-user');
    fs.mkdirSync(path.dirname(file), { recursive: true });
    fs.writeFileSync(file, atlasUser);
    return true;
}
export function registerSkillsMigrateBack(program) {
    const skills = program.commands.find((c) => c.name() === 'skills') ??
        program.command('skills').description('Manage skill sources and synchronization');
    skills
        .command(MIGRATE_BACK_TO_TOOLBOX_COMMAND)
        .description('Reverse migrate-from-toolbox using the pre-migration snapshot')
        .option('--path <path>', 'Absolute path of the original toolbox repo (filters to the snapshot taken for this source)')
        .option('--namespace <name>', 'Filter snapshots by namespace (e.g. atlas-toolbox, ai-skills)')
        .option('--snapshot <path>', 'Use a specific snapshot file (default: most recent matching snapshot)')
        .option('--keep-source', 'Preserve the toolbox olam source registration (default: remove)')
        .action((opts) => {
        // 1. Resolve snapshot.
        let snapshotPath;
        let snapshot;
        try {
            if (opts.snapshot) {
                snapshotPath = path.resolve(opts.snapshot);
                if (!fs.existsSync(snapshotPath)) {
                    printError(`snapshot not found at ${snapshotPath}`);
                    process.exitCode = 1;
                    return;
                }
                snapshot = readMigrationSnapshotFromPath(snapshotPath);
            }
            else {
                const filterNamespace = opts.namespace ?? (opts.path ? path.basename(opts.path) : undefined);
                const latest = readLatestMigrationSnapshot({ namespace: filterNamespace });
                if (!latest) {
                    const where = filterNamespace ? ` for namespace "${filterNamespace}"` : '';
                    printError(`no migration snapshot found${where}. Did you run \`olam skills migrate-from-toolbox\` first?`);
                    process.exitCode = 1;
                    return;
                }
                snapshotPath = latest.path;
                snapshot = latest.snapshot;
            }
        }
        catch (err) {
            printError(`could not read snapshot: ${asMessage(err)}`);
            process.exitCode = 1;
            return;
        }
        // If --path was supplied as an additional sanity check, warn on mismatch
        // but proceed (the snapshot is authoritative about what to restore).
        if (opts.path && snapshot.atlasToolboxRepoPath && opts.path !== snapshot.atlasToolboxRepoPath) {
            printWarning(`--path ${opts.path} differs from snapshot's recorded path ${snapshot.atlasToolboxRepoPath}; proceeding with snapshot's path`);
        }
        printInfo('snapshot', snapshotPath);
        // 2. Uninstall olam-skills hook.
        try {
            const settingsFile = claudeSettingsPath();
            const r = uninstallSkillsHookFromFile(settingsFile);
            printInfo('olam hook', r.status);
        }
        catch (err) {
            printWarning(`olam hook uninstall failed: ${asMessage(err)}; proceeding`);
        }
        // 3. Remove olam-managed symlinks BEFORE removing the source
        //    registration (we need source paths to identify them).
        const olamSymlinksRemoved = removeOlamManagedSymlinks();
        printInfo('olam symlinks removed', String(olamSymlinksRemoved));
        // 4. Restore original SessionStart hook block.
        try {
            const r = restoreSessionStartFromSnapshot(claudeSettingsPath(), snapshot.originalSessionStartHook);
            printInfo('original hook', r.restored ? 'restored' : 'no original hook in snapshot');
        }
        catch (err) {
            printWarning(`original hook restore failed: ${asMessage(err)}; proceeding`);
        }
        // 5. Restore toolbox symlinks.
        const restored = restoreToolboxSymlinks(snapshot.atlasManagedSymlinks ?? []);
        printInfo('toolbox symlinks restored', String(restored));
        // 6. Restore .atlas-user marker (atlas-toolbox-shape only; no-op for non-atlas sources).
        const atlasUserRestored = restoreAtlasUserMarker(snapshot.atlasUser);
        if (atlasUserRestored)
            printInfo('atlas-user', `restored ("${snapshot.atlasUser}")`);
        // 7. Remove olam source registration (unless --keep-source).
        if (!opts.keepSource) {
            try {
                const sources = listSkillSources();
                const target = snapshot.atlasToolboxRepoPath;
                const namespace = snapshot.namespace;
                for (const s of sources) {
                    if (s.gitUrl === target || (namespace && s.name === namespace)) {
                        removeSkillSourceClone(s.id);
                        removeSkillSource(s.id);
                        printInfo('olam source removed', `${s.name} (${s.id})`);
                    }
                }
            }
            catch (err) {
                printWarning(`source removal failed: ${asMessage(err)}; proceeding`);
            }
        }
        else {
            printInfo('olam source', '--keep-source: preserved');
        }
        printSuccess(`migrated back — toolbox state restored from snapshot taken at ${snapshot.takenAt}`);
    });
}
//# sourceMappingURL=skills-migrate-back.js.map