/**
 * `olam skills migrate-from-toolbox` — convert an existing toolbox-shaped
 * skill source (e.g. atlas-toolbox, grain/ai-skills) installation to
 * olam-managed skill distribution.
 *
 * Order of operations (atomic in spirit — snapshot first, mutations after):
 *   1. detectToolboxState({ toolboxPath }) → MigrationSnapshot (or no-op when nothing detected)
 *   2. writeMigrationSnapshot() → ~/.olam/state/migration-snapshots/<namespace>-<ISO>.json
 *   3. addSkillSource() + cloneSkillSource() → register the toolbox as an olam source
 *   4. uninstall legacy toolbox SessionStart hook entries (entries whose command
 *      references the toolbox repo path OR `./scripts/sync.sh`)
 *   5. install the olam-skills SessionStart hook (via mergeHomeSettingsJson)
 *   6. run `olam skills sync` to deploy artifacts under olam management
 *
 * Idempotent: re-running on an already-migrated host detects the olam
 * hook sentinel and no-ops with an informative message.
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import { addSkillSource, cloneSkillSource, detectToolboxState, writeMigrationSnapshot, OLAM_SKILLS_HOOK_SENTINEL, buildSkillsHookEntry, OLAM_SKILLS_HOOK_STAGE, syncSkills, } from '@olam/core/src/skill-sources/index.js';
import { mergeHomeSettingsJson } from '@olam/core/src/world/merge-settings.js';
import { claudeSettingsPath } 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_FROM_TOOLBOX_COMMAND = 'migrate-from-toolbox';
function asMessage(err) {
    return err instanceof Error ? err.message : String(err);
}
function isOlamSkillsHookPresent(filePath) {
    if (!fs.existsSync(filePath))
        return false;
    try {
        const raw = fs.readFileSync(filePath, 'utf-8');
        return raw.includes(OLAM_SKILLS_HOOK_SENTINEL);
    }
    catch {
        return false;
    }
}
/**
 * Surgically remove SessionStart hook entries that reference the toolbox
 * repo path OR call `./scripts/sync.sh` (legacy atlas-toolbox sync entry —
 * harmless no-op against non-atlas toolboxes). Leaves olam-skills entries
 * and unrelated user hooks intact.
 */
function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
    if (!fs.existsSync(filePath))
        return { removed: 0 };
    const raw = fs.readFileSync(filePath, 'utf-8');
    const settings = raw.trim() ? JSON.parse(raw) : {};
    const ss = settings?.hooks?.SessionStart;
    if (!Array.isArray(ss))
        return { removed: 0 };
    let removed = 0;
    const filteredMatchers = [];
    for (const matcher of ss) {
        const innerHooks = Array.isArray(matcher?.hooks) ? matcher.hooks : [];
        const keptInner = innerHooks.filter((h) => {
            if (typeof h?.command !== 'string')
                return true;
            // Identify legacy-toolbox-shape entries by command content.
            const looksLegacyToolbox = h.command.includes('./scripts/sync.sh') ||
                (toolboxPath !== undefined && h.command.includes(toolboxPath));
            // Never remove olam-skills entries here — install-skills-hook handles those.
            const isOlam = h.command.includes(OLAM_SKILLS_HOOK_SENTINEL);
            if (looksLegacyToolbox && !isOlam) {
                removed += 1;
                return false;
            }
            return true;
        });
        if (keptInner.length === 0 && innerHooks.length > 0)
            continue;
        if (keptInner.length === innerHooks.length)
            filteredMatchers.push(matcher);
        else
            filteredMatchers.push({ ...matcher, hooks: keptInner });
    }
    if (removed === 0)
        return { removed: 0 };
    const next = { ...settings, hooks: { ...settings.hooks, SessionStart: filteredMatchers } };
    if (filteredMatchers.length === 0) {
        const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== 'SessionStart');
        if (otherStages.length === 0)
            delete next.hooks;
        else
            delete next.hooks.SessionStart;
    }
    fs.writeFileSync(filePath, JSON.stringify(next, null, 2) + '\n');
    return { removed };
}
export function registerSkillsMigrate(program) {
    const skills = program.commands.find((c) => c.name() === 'skills') ??
        program.command('skills').description('Manage skill sources and synchronization');
    skills
        .command(MIGRATE_FROM_TOOLBOX_COMMAND)
        .description('Convert an existing toolbox-shaped skill source (atlas-toolbox, grain/ai-skills, etc.) to olam-managed skill distribution')
        .option('--path <path>', 'Absolute path to the source toolbox repo (e.g. /repos/atlas-toolbox, /repos/grain/ai-skills)')
        .option('--namespace <name>', 'Source-identifying namespace used for the snapshot filename + default source name (default: basename of --path)')
        .option('--source-name <name>', 'Display name for the registered olam source (default: --namespace)')
        .option('--branch <branch>', 'Branch to track on the source', 'master')
        .option('--scope <scope>', 'install-hook scope: project (default) or user', 'project')
        .option('--no-clone', 'Skip clone step (register source state only — useful for tests)')
        .action(async (opts) => {
        // Idempotency: if olam-skills sentinel already present, no-op.
        const settingsFile = claudeSettingsPath();
        if (isOlamSkillsHookPresent(settingsFile)) {
            printInfo(MIGRATE_FROM_TOOLBOX_COMMAND, `already migrated (olam-skills hook sentinel present in ${settingsFile})`);
            return;
        }
        if (!opts.path) {
            printError('--path <path> is required (absolute path to the source toolbox repo, e.g. /repos/atlas-toolbox)');
            process.exitCode = 1;
            return;
        }
        const toolboxPath = opts.path;
        const namespace = opts.namespace ?? path.basename(toolboxPath);
        const sourceName = opts.sourceName ?? namespace;
        // 1. Detect.
        const snapshot = detectToolboxState({ toolboxPath, namespace });
        if (!snapshot) {
            printInfo(MIGRATE_FROM_TOOLBOX_COMMAND, `no toolbox state detected at ${toolboxPath} (no ~/.claude/.atlas-user, no symlinks pointing at this path, no SessionStart hook block — nothing to migrate)`);
            return;
        }
        // 2. Snapshot (ALWAYS — before any mutation).
        let snapshotPath;
        try {
            snapshotPath = writeMigrationSnapshot(snapshot);
            printInfo('snapshot', snapshotPath);
        }
        catch (err) {
            printError(`snapshot write failed: ${asMessage(err)}`);
            process.exitCode = 1;
            return;
        }
        // 3. Register source + clone.
        // `trustMethod: 'internal'` — migrate-from is an operator-explicit
        // command (operator typed it). Bypasses the interactive trust
        // gate but is structurally audit-logged via addSkillSource()
        // itself; the trust-audit log records the bypass.
        try {
            const entry = addSkillSource({
                name: sourceName,
                gitUrl: toolboxPath,
                branch: opts.branch,
                trustMethod: 'internal',
            });
            printInfo('registered source', `${entry.name} (${entry.id})`);
            if (opts.clone !== false) {
                const cloneResult = cloneSkillSource({
                    gitUrl: entry.gitUrl,
                    branch: entry.branch,
                    id: entry.id,
                });
                printInfo('cloned to', cloneResult.clonePath);
            }
            else {
                printInfo('clone skipped', '--no-clone passed');
            }
        }
        catch (err) {
            printError(`source registration failed: ${asMessage(err)}`);
            printInfo('snapshot preserved', snapshotPath);
            process.exitCode = 1;
            return;
        }
        // 4. Uninstall legacy toolbox SessionStart hook.
        try {
            const surgery = uninstallLegacyToolboxSessionStartHook(settingsFile, toolboxPath);
            if (surgery.removed > 0) {
                printInfo('legacy hook', `removed ${surgery.removed} entry(ies) from ${settingsFile}`);
            }
            else {
                printInfo('legacy hook', 'no legacy-toolbox-shape SessionStart hook entries found');
            }
        }
        catch (err) {
            printWarning(`legacy hook removal failed: ${asMessage(err)}; proceeding`);
        }
        // 5. Install olam-skills hook.
        const scope = opts.scope === 'user' ? 'user' : 'project';
        const olamHookPath = scope === 'user' ? settingsFile : path.join(process.cwd(), '.claude', 'settings.json');
        try {
            fs.mkdirSync(path.dirname(olamHookPath), { recursive: true });
            const result = mergeHomeSettingsJson(olamHookPath, {
                ensureHook: {
                    stage: OLAM_SKILLS_HOOK_STAGE,
                    sentinel: OLAM_SKILLS_HOOK_SENTINEL,
                    entry: buildSkillsHookEntry(),
                },
            });
            printInfo('olam hook', `${result.status} at ${olamHookPath}`);
        }
        catch (err) {
            printError(`olam hook install failed: ${asMessage(err)}`);
            printInfo('snapshot preserved', snapshotPath);
            process.exitCode = 1;
            return;
        }
        // 6. Sync.
        try {
            const summary = await syncSkills({ atlasUser: snapshot.atlasUser });
            printSuccess(`migrated — synced ${summary.sourceCount} source(s), deployed ${summary.deploy?.linked ?? 0} symlink(s)`);
            printInfo('snapshot', snapshotPath);
            printInfo('reverse', `run \`olam skills migrate-back-to-toolbox --path ${toolboxPath}\` to restore the original state`);
        }
        catch (err) {
            printError(`sync failed: ${asMessage(err)}`);
            printInfo('snapshot preserved', snapshotPath);
            process.exitCode = 1;
        }
    });
}
// Export internal helper for tests + reverse-migration consumers.
export { uninstallLegacyToolboxSessionStartHook };
//# sourceMappingURL=skills-migrate.js.map