// Task 165 — bundled-specialist registration.
//
// Claude Code resolves `--agent <name>` by reading
// `$CLAUDE_CONFIG_DIR/agents/<name>.md`. The installer ships every
// bundled specialist as a file under
// `<INSTALL_DIR>/platform/templates/specialists/agents/*.md`; this
// module symlinks each into the per-brand `$CLAUDE_CONFIG_DIR/agents/`
// so `claude --agent database-operator` resolves on first call.
//
// Idempotent. Re-running the installer after a template change
// refreshes stale symlinks. A regular file at the destination is a
// collision — never silently overwritten; the operator must remove it
// explicitly (we throw and the caller decides whether to exit).
//
// Lives outside index.ts so unit tests can import the function without
// triggering index.ts top-level installer code (which fatals on missing
// brand.json in a test environment).
import { existsSync, mkdirSync, readdirSync, lstatSync, readlinkSync, symlinkSync, unlinkSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
export class SpecialistSymlinkCollision extends Error {
    linkPath;
    constructor(linkPath) {
        super(`${linkPath} collision (regular file) — remove and re-run`);
        this.linkPath = linkPath;
        this.name = "SpecialistSymlinkCollision";
    }
}
export function registerSpecialistAgentsAt(templatesDir, agentsDir, log = () => { }) {
    if (!existsSync(templatesDir)) {
        log(`  [specialist-registration] SKIPPED reason=templates-dir-missing path=${templatesDir}`);
        return { registered: [], skipped: 'no-templates-dir' };
    }
    mkdirSync(agentsDir, { recursive: true });
    const entries = readdirSync(templatesDir).filter((n) => n.endsWith(".md"));
    if (entries.length === 0) {
        log(`  [specialist-registration] SKIPPED reason=no-bundled-specialists path=${templatesDir}`);
        return { registered: [], skipped: 'no-bundled-specialists' };
    }
    const registered = [];
    for (const file of entries.sort()) {
        const targetAbs = join(templatesDir, file);
        const linkPath = join(agentsDir, file);
        const name = file.replace(/\.md$/, "");
        replaceSpecialistSymlink(linkPath, targetAbs);
        registered.push(name);
        log(`  [specialist-registration] installer-specialist-registered name=${name} link=${targetAbs}`);
    }
    return { registered, skipped: null };
}
export function replaceSpecialistSymlink(linkPath, targetAbs) {
    let lstat = null;
    try {
        lstat = lstatSync(linkPath);
    }
    catch (err) {
        const code = err.code;
        if (code !== "ENOENT")
            throw err;
    }
    if (lstat === null) {
        symlinkSync(targetAbs, linkPath);
        return;
    }
    if (!lstat.isSymbolicLink()) {
        throw new SpecialistSymlinkCollision(linkPath);
    }
    let resolvedTarget;
    try {
        resolvedTarget = resolve(dirname(linkPath), readlinkSync(linkPath));
    }
    catch {
        resolvedTarget = "<unreadable>";
    }
    if (resolvedTarget === targetAbs)
        return;
    unlinkSync(linkPath);
    symlinkSync(targetAbs, linkPath);
}
