// engine/release/rollback-runner.ts — SPEC-737: Rollback orchestration logic
// Executes npm dist-tag rm → git tag -d → git push --delete origin in order.
import { spawn } from 'node:child_process';
// ---------------------------------------------------------------------------
// Internal: run a shell command
// ---------------------------------------------------------------------------
async function runCmd(cmd, args, options) {
    return new Promise((resolve) => {
        const child = spawn(cmd, args, {
            cwd: options?.cwd ?? process.cwd(),
            stdio: ['ignore', 'pipe', 'pipe'],
        });
        let stdout = '';
        let stderr = '';
        child.stdout.on('data', (d) => {
            stdout += d.toString();
        });
        child.stderr.on('data', (d) => {
            stderr += d.toString();
        });
        child.on('close', (code) => {
            resolve({ exitCode: code ?? 1, stdout, stderr });
        });
        child.on('error', (err) => {
            resolve({ exitCode: 1, stdout: '', stderr: err.message });
        });
    });
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Determine the dist-tag for a given version via `npm dist-tag ls`.
 * Returns 'latest' if the version is tagged as latest, otherwise 'beta' or first found tag.
 * Falls back to 'latest' on error.
 */
export async function detectDistTag(packageName, version) {
    const result = await runCmd('npm', ['dist-tag', 'ls', packageName]);
    if (result.exitCode !== 0) {
        return 'latest';
    }
    const lines = result.stdout.split('\n').filter((l) => l.trim());
    for (const line of lines) {
        const [tag, ver] = line.split(': ').map((s) => s.trim());
        if (ver === version && tag) {
            return tag;
        }
    }
    return 'latest';
}
/**
 * Run the rollback steps:
 *   1. npm dist-tag rm @planu/cli <tag>
 *   2. git tag -d v<version>
 *   3. git push --delete origin v<version>
 *
 * Halts on first failure. Returns the list of steps with their statuses.
 */
export async function runRollback(input) {
    const { version, packageName = '@planu/cli', dryRun = false } = input;
    const gitTag = `v${version}`;
    const steps = [];
    // ── Step 1: npm dist-tag rm ───────────────────────────────────────────────
    const distTag = dryRun ? 'latest' : await detectDistTag(packageName, version);
    if (dryRun) {
        steps.push({
            name: 'npm-dist-tag-rm',
            status: 'success',
            command: `npm dist-tag rm ${packageName} ${distTag} (dry-run)`,
            stdout: '[dry-run]',
        });
    }
    else {
        const npmResult = await runCmd('npm', ['dist-tag', 'rm', packageName, distTag]);
        const npmStep = {
            name: 'npm-dist-tag-rm',
            status: npmResult.exitCode === 0 ? 'success' : 'failed',
            command: `npm dist-tag rm ${packageName} ${distTag}`,
            stdout: npmResult.stdout,
            stderr: npmResult.stderr,
        };
        steps.push(npmStep);
        if (npmStep.status === 'failed') {
            return { ok: false, steps, failedStep: 'npm-dist-tag-rm' };
        }
    }
    // ── Step 2: git tag -d v<version> ────────────────────────────────────────
    if (dryRun) {
        steps.push({
            name: 'git-tag-delete-local',
            status: 'success',
            command: `git tag -d ${gitTag} (dry-run)`,
            stdout: '[dry-run]',
        });
    }
    else {
        const gitLocalResult = await runCmd('git', ['tag', '-d', gitTag]);
        const gitLocalStep = {
            name: 'git-tag-delete-local',
            status: gitLocalResult.exitCode === 0 ? 'success' : 'failed',
            command: `git tag -d ${gitTag}`,
            stdout: gitLocalResult.stdout,
            stderr: gitLocalResult.stderr,
        };
        steps.push(gitLocalStep);
        if (gitLocalStep.status === 'failed') {
            return { ok: false, steps, failedStep: 'git-tag-delete-local' };
        }
    }
    // ── Step 3: git push --delete origin v<version> ──────────────────────────
    if (dryRun) {
        steps.push({
            name: 'git-tag-delete-remote',
            status: 'success',
            command: `git push --delete origin ${gitTag} (dry-run)`,
            stdout: '[dry-run]',
        });
    }
    else {
        const gitRemoteResult = await runCmd('git', ['push', '--delete', 'origin', gitTag]);
        const gitRemoteStep = {
            name: 'git-tag-delete-remote',
            status: gitRemoteResult.exitCode === 0 ? 'success' : 'failed',
            command: `git push --delete origin ${gitTag}`,
            stdout: gitRemoteResult.stdout,
            stderr: gitRemoteResult.stderr,
        };
        steps.push(gitRemoteStep);
        if (gitRemoteStep.status === 'failed') {
            return { ok: false, steps, failedStep: 'git-tag-delete-remote' };
        }
    }
    return { ok: true, steps };
}
//# sourceMappingURL=rollback-runner.js.map