"use strict";
// src/cli/DeployCommand.ts
// v1.18.0 — `openlife deploy [--provider=vercel|railway] [--preview] [rollback]`
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerDeployCommand = registerDeployCommand;
const DeployAdapter_1 = require("../orchestrator/deploy/DeployAdapter");
function emitJson(obj) {
    process.stdout.write(`${JSON.stringify(obj, null, 2)}\n`);
}
async function resolveProvider(opts) {
    if (opts.provider)
        return opts.provider;
    return DeployAdapter_1.DeployRegistry.autoDetect();
}
async function deployCmd(opts) {
    const provider = await resolveProvider(opts);
    if (!provider) {
        emitJson({
            ok: false,
            error: 'no_provider_detected',
            hint: 'Install `vercel` or `railway` CLI, or pass --provider=<name>. Detected markers: vercel.json, railway.toml, .vercel/, railway.json.',
        });
        process.exitCode = 1;
        return;
    }
    const adapter = DeployAdapter_1.DeployRegistry.get(provider);
    if (!adapter) {
        emitJson({ ok: false, error: `adapter_not_registered: ${provider}` });
        process.exitCode = 1;
        return;
    }
    if (!(await adapter.detect())) {
        emitJson({
            ok: false,
            provider,
            error: `cli_not_installed: ${provider}`,
            hint: `Install the ${provider} CLI (https://${provider}.com/docs/cli)`,
        });
        process.exitCode = 1;
        return;
    }
    if (!opts.skipPreflight) {
        const pre = await adapter.preflight({ preview: opts.preview, target: opts.target });
        if (!opts.json) {
            for (const i of pre.issues) {
                const prefix = i.severity === 'error' ? '❌' : '⚠';
                process.stderr.write(`${prefix} preflight: ${i.message}${i.hint ? ` — ${i.hint}` : ''}\n`);
            }
        }
        if (!pre.ok) {
            if (opts.json)
                emitJson({ ok: false, provider, preflight: pre });
            process.exitCode = 1;
            return;
        }
    }
    const result = await adapter.deploy({
        preview: opts.preview,
        target: opts.target,
        timeoutMs: opts.timeoutMs,
    });
    if (opts.json) {
        emitJson(result);
        if (!result.ok)
            process.exitCode = 1;
        return;
    }
    if (result.ok) {
        process.stdout.write(`\n✓ Deployed to ${result.provider}${opts.preview ? ' (preview)' : ' (production)'}\n`);
        if (result.url)
            process.stdout.write(`  URL: ${result.url}\n`);
        if (result.deploymentId)
            process.stdout.write(`  ID:  ${result.deploymentId}\n`);
        process.stdout.write(`  Duration: ${(result.durationMs / 1000).toFixed(1)}s\n`);
    }
    else {
        process.stderr.write(`\n❌ Deploy failed: ${result.error || 'unknown'}\n`);
        process.exitCode = 1;
    }
}
async function rollbackCmd(opts) {
    const provider = opts.provider || (await DeployAdapter_1.DeployRegistry.autoDetect());
    if (!provider) {
        emitJson({ ok: false, error: 'no_provider_detected' });
        process.exitCode = 1;
        return;
    }
    const adapter = DeployAdapter_1.DeployRegistry.get(provider);
    if (!adapter) {
        emitJson({ ok: false, error: `adapter_not_registered: ${provider}` });
        process.exitCode = 1;
        return;
    }
    const result = await adapter.rollback({ to: opts.to });
    if (opts.json) {
        emitJson(result);
    }
    else if (result.ok) {
        process.stdout.write(`\n✓ Rolled back ${provider}\n`);
        if (result.url)
            process.stdout.write(`  URL: ${result.url}\n`);
    }
    else {
        process.stderr.write(`\n❌ Rollback failed: ${result.error || 'unknown'}\n`);
    }
    if (!result.ok)
        process.exitCode = 1;
}
async function promoteCmd(env, opts) {
    if (!env) {
        emitJson({ ok: false, error: 'promote_requires_env', hint: 'Usage: openlife deploy promote <env> [--from <id>] [--provider <name>]' });
        process.exitCode = 1;
        return;
    }
    const provider = opts.provider || (await DeployAdapter_1.DeployRegistry.autoDetect());
    if (!provider) {
        emitJson({ ok: false, error: 'no_provider_detected' });
        process.exitCode = 1;
        return;
    }
    const adapter = DeployAdapter_1.DeployRegistry.get(provider);
    if (!adapter) {
        emitJson({ ok: false, error: `adapter_not_registered: ${provider}` });
        process.exitCode = 1;
        return;
    }
    const result = await adapter.promote({
        to: env,
        from: opts.from,
        domain: opts.domain,
        timeoutMs: opts.timeoutMs,
    });
    if (opts.json) {
        emitJson(result);
    }
    else if (result.ok) {
        process.stdout.write(`\n✓ Promoted to ${env} on ${provider}\n`);
        if (result.url)
            process.stdout.write(`  URL: ${result.url}\n`);
        if (result.deploymentId)
            process.stdout.write(`  From: ${result.deploymentId}\n`);
        process.stdout.write(`  Duration: ${(result.durationMs / 1000).toFixed(1)}s\n`);
    }
    else {
        process.stderr.write(`\n❌ Promote failed: ${result.error || 'unknown'}\n`);
    }
    if (!result.ok)
        process.exitCode = 1;
}
async function listCmd(opts) {
    const providers = DeployAdapter_1.DeployRegistry.list();
    if (opts.json) {
        emitJson({ ok: true, providers });
        return;
    }
    process.stdout.write(`Available deploy providers:\n`);
    for (const p of providers) {
        const adapter = DeployAdapter_1.DeployRegistry.get(p);
        const detected = adapter ? await adapter.detect() : false;
        process.stdout.write(`  ${p.padEnd(12)} ${detected ? '✓ installed' : '✗ CLI not on PATH'}\n`);
    }
}
function registerDeployCommand(program) {
    const d = program
        .command('deploy')
        .description('v1.18.0 — Deploy to a provider (Vercel, Railway). Auto-detects from vercel.json / railway.toml.');
    d.option('--provider <name>', 'Force a provider: vercel | railway')
        .option('--preview', 'Preview deploy (ephemeral URL) instead of production')
        .option('--target <name>', 'Provider-specific target (e.g. Vercel scope, Railway service)')
        .option('--timeout-ms <ms>', 'Wall-clock cap on the deploy CLI (default 600000)', (v) => Number(v))
        .option('--skip-preflight', 'Bypass preflight checks (env, project link, config)')
        .option('--json', 'Emit JSON result')
        .action((opts) => { void deployCmd(opts); });
    d.command('rollback')
        .description('Roll back to a previous deployment')
        .option('--provider <name>', 'Force a provider')
        .option('--to <deploymentId>', 'Specific deployment to roll back TO (default: last good)')
        .option('--json', 'Emit JSON result')
        .action((opts) => { void rollbackCmd(opts); });
    d.command('promote <env>')
        .description('v1.19.0 — Promote an existing deployment to a target environment (alias swap or redeploy)')
        .option('--provider <name>', 'Force a provider: vercel | railway | cloudflare | fly')
        .option('--from <deploymentId>', 'Source deployment URL/id (alias-swap providers only)')
        .option('--domain <domain>', 'Target domain (alias-swap providers only)')
        .option('--timeout-ms <ms>', 'Wall-clock cap on the promote CLI', (v) => Number(v))
        .option('--json', 'Emit JSON result')
        .action((env, opts) => { void promoteCmd(env, opts); });
    d.command('list')
        .description('List available deploy adapters + installed CLIs')
        .option('--json', 'Emit JSON result')
        .action((opts) => { void listCmd(opts); });
}
