/**
 * `olam worldspec init [--from-adb-yaml]` — scaffold a `default.yaml`
 * worldspec in the current repo. Detects project shape from existing
 * files (package.json / Gemfile / .ruby-version / .adb.yaml) and seeds
 * sensible capability defaults.
 *
 * Output: `<cwd>/.olam/worldspecs/default.yaml`
 *
 * Idempotent: refuses to overwrite an existing file unless `--force`.
 * Emits a clear next-step UX line on success (closes Decision-#11
 * onboarding banner gap surfaced in plan body).
 */
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { execSync } from 'node:child_process';
import { basename, dirname, resolve as resolvePath } from 'node:path';
import { EXIT_GENERIC_ERROR, EXIT_WORLDSPEC_EXISTS, } from '../../exit-codes.js';
import { printError, printSuccess } from '../../output.js';
export function registerWorldspecInit(parent) {
    parent
        .command('init')
        .description('Scaffold a default.yaml worldspec in the current repo (.olam/worldspecs/)')
        .option('--force', 'Overwrite an existing .olam/worldspecs/default.yaml', false)
        .option('--from-adb-yaml', 'Read project shape from .adb.yaml when present', false)
        .action((opts) => {
        const cwd = process.cwd();
        const targetDir = resolvePath(cwd, '.olam/worldspecs');
        const targetFile = resolvePath(targetDir, 'default.yaml');
        if (existsSync(targetFile) && !opts.force) {
            printError(`${targetFile} already exists; pass --force to overwrite`);
            // MEDIUM fix (A3 CP3 audit 2026-05-09): EXIT_WORLDSPEC_EXISTS
            // distinguishes "you forgot --force" from EXIT_GENERIC_ERROR=1
            // (internal/parse crash). Pipelines that grep $? can branch.
            process.exit(EXIT_WORLDSPEC_EXISTS);
        }
        // MEDIUM fix (A3 CP3 audit 2026-05-09): warn-then-exit on
        // --from-adb-yaml — flag was a dead stub (presence-only). Either
        // ship parser or surface explicit "not yet implemented" so
        // operators don't assume their .adb.yaml shape was read.
        if (opts.fromAdbYaml) {
            printError('--from-adb-yaml is not yet implemented (deferred to v1.1); ' +
                'remove the flag and re-run, or proceed with manual edit.');
            process.exit(EXIT_GENERIC_ERROR);
        }
        const shape = detectProjectShape(cwd, opts.fromAdbYaml);
        const yaml = renderWorldspecYaml(shape);
        try {
            mkdirSync(targetDir, { recursive: true });
            // MEDIUM fix (A3 CP3 audit 2026-05-09): use 'wx' flag in
            // non-force path AND open with 'w' explicitly when --force.
            // 'wx' refuses if the path exists OR is a symlink → closes
            // TOCTOU between existsSync above and writeFileSync below.
            // (existsSync gate above is the user-facing UX; 'wx' is the
            // race-resistant lower-bound guarantee.)
            writeFileSync(targetFile, yaml, {
                encoding: 'utf8',
                flag: opts.force ? 'w' : 'wx',
            });
        }
        catch (err) {
            printError(`failed to scaffold ${targetFile}: ${err.message}`);
            process.exit(EXIT_GENERIC_ERROR);
        }
        printSuccess(`scaffolded ${targetFile}`);
        // Two-arg printInfo expects (label, value); craft a label-less line
        // via console.log so the next-step UX renders cleanly without padding.
        console.log(`  Edit it to fit your repo, then run: olam worldspec validate ${relativeFromCwd(targetFile, cwd)}`);
        process.exit(0);
    });
}
function detectProjectShape(root, useAdbYaml) {
    const hasGemfile = existsSync(resolvePath(root, 'Gemfile'));
    const hasNodePackageJson = existsSync(resolvePath(root, 'package.json'));
    const hasAdbYaml = existsSync(resolvePath(root, '.adb.yaml'));
    let rubyVersion = null;
    const rubyVersionPath = resolvePath(root, '.ruby-version');
    if (existsSync(rubyVersionPath)) {
        try {
            const raw = readFileSync(rubyVersionPath, 'utf8').trim();
            // .ruby-version can be `3.3.0` or `ruby-3.3.0`; extract the SemVer.
            const match = raw.match(/(\d+\.\d+\.\d+)/);
            if (match)
                rubyVersion = match[1] ?? null;
        }
        catch {
            // ignore — fall back to null
        }
    }
    // --from-adb-yaml is a future hook (parse .adb.yaml's runtime block);
    // for v1 we just record presence so the scaffolded YAML's comment
    // references it correctly. Real adb-yaml parsing is deferred to v2.
    void useAdbYaml;
    return {
        repoName: getRepoName(root),
        hasGemfile,
        rubyVersion,
        hasNodePackageJson,
        hasAdbYaml,
    };
}
function getRepoName(root) {
    try {
        const url = execSync('git remote get-url origin', {
            cwd: root,
            encoding: 'utf-8',
            stdio: ['ignore', 'pipe', 'ignore'],
        }).trim();
        const match = url.match(/\/([^/]+?)(?:\.git)?$/);
        if (match && match[1])
            return match[1];
    }
    catch {
        // not a git repo or no origin; fall back to dir basename
    }
    return basename(root);
}
function renderWorldspecYaml(shape) {
    const lines = [];
    lines.push('# Scaffolded by `olam worldspec init`. Edit to fit your repo.');
    if (shape.hasAdbYaml) {
        lines.push('# Detected .adb.yaml — consider migrating its runtime + service blocks here.');
    }
    lines.push('schemaVersion: 1');
    lines.push(`name: ${kebab(shape.repoName)}-default`);
    lines.push('description: ""');
    lines.push('repos:');
    // MEDIUM fix (A3 CP3 audit 2026-05-09): kebab the repoName before
    // emitting into YAML — git remote URLs can contain newlines / colons
    // that smuggle YAML structure if interpolated raw (covered by name:
    // line via kebab() but missed here in the first commit).
    lines.push(`  - ${kebab(shape.repoName)}`);
    lines.push('images:');
    lines.push('  devbox: ghcr.io/REPLACE_ME/olam-devbox:latest');
    lines.push('  imageSource: local-first');
    lines.push('capabilities:');
    if (shape.hasGemfile) {
        lines.push('  - type: runtime.ruby');
        lines.push(`    version: "${shape.rubyVersion ?? '3.3.0'}"`);
        lines.push(`    forRepo: ${kebab(shape.repoName)}`);
        lines.push('  - type: database.postgres');
        lines.push('    version: "13"');
    }
    if (shape.hasNodePackageJson && !shape.hasGemfile) {
        lines.push('  # Node.js project detected. runtime.node is deferred to v1.1');
        lines.push('  # (boot-d hook can pin node version in the meantime).');
    }
    lines.push('  - type: auth.ghcr');
    lines.push('    scopes:');
    lines.push('      - read:packages');
    lines.push('  - type: dispatch.readiness');
    lines.push('    mode: regex');
    lines.push('    pattern: "❯"');
    lines.push('');
    return lines.join('\n');
}
function kebab(s) {
    return s
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/^-+|-+$/g, '');
}
function relativeFromCwd(absPath, cwd) {
    if (absPath.startsWith(cwd + '/'))
        return absPath.slice(cwd.length + 1);
    return absPath;
}
//# sourceMappingURL=init.js.map