import { getWriter, getDetector } from './registry.js';
/**
 * Kinds prune reconciles. Restricted to the name-keyed file/dir resources whose
 * writer implements `remove()`. Deliberately excluded, each with a reason:
 *   - hooks — a version-home hook script is coupled to a settings.json /
 *     hooks.json REGISTRATION. Pruning the last hook to zero would delete the
 *     script but must also GC its registration in the same pass, and that lands
 *     in `src/lib/hooks/install.ts` — a Windows-portable-path surface the CI windows leg
 *     gates on. Split to RUSH-2456 so this PR stays Linux-only-green; hook FILES
 *     are still reconciled by the in-write orphan sweep (versions.ts, gated on
 *     `hooksToSync > 0`).
 *   - rules / permissions — synced as a wholesale rewrite (one composed file /
 *     the full allowlist), so a removed rule or group already drops out.
 *   - plugins — carry their own reconciliation via `cleanOrphanedPluginSkills`.
 *   - mcp — registered through each agent's CLI/config, a separate removal path.
 *   - subagents / workflows — no clean per-name inverse yet (multi-agent index
 *     finalize; native workflow trees); tracked for a follow-up.
 */
export const PRUNABLE_KINDS = ['commands', 'skills'];
/** Names the manifest recorded as installed for a kind (source-name keyed). */
function manifestNames(manifest, kind) {
    switch (kind) {
        case 'commands': {
            // Object keys are the source command names; writtenCommands carries any
            // extra names the writer actually emitted (dual-write / command-skill).
            const names = new Set(Object.keys(manifest.commands ?? {}));
            for (const c of manifest.writtenCommands ?? [])
                names.add(c);
            return [...names];
        }
        case 'skills': return Object.keys(manifest.skills ?? {});
    }
}
function emptyPruned() {
    return { commands: [], skills: [] };
}
/**
 * Remove resources that a prior sync installed and that are now gone from
 * source, from one agent@version home. Deletes nothing when no manifest exists.
 */
export function pruneRemovedResources(input) {
    const { agent, version, versionHome, cwd, previousManifest, sourceNames } = input;
    if (!previousManifest) {
        return { pruned: emptyPruned(), skippedNoManifest: true };
    }
    const pruned = emptyPruned();
    for (const kind of PRUNABLE_KINDS) {
        const writer = getWriter(kind, agent);
        const detector = getDetector(kind, agent);
        // No writer.remove (unsupported kind/agent) or no detector: nothing to do.
        if (!writer?.remove || !detector)
            continue;
        const installed = manifestNames(previousManifest, kind);
        if (installed.length === 0)
            continue;
        const stillInSource = new Set(sourceNames[kind]);
        const materialized = new Set(detector.list({ version, versionHome, cwd }));
        for (const name of installed) {
            if (stillInSource.has(name))
                continue; // still provided by some layer
            if (!materialized.has(name))
                continue; // already gone from the home
            const result = writer.remove({ version, versionHome, name, cwd });
            if (result.removed)
                pruned[kind].push(name);
        }
    }
    return { pruned, skippedNoManifest: false };
}
