"use strict";
// src/orchestrator/deploy/CloudflareAdapter.ts
// v1.18.1 — Wraps the `wrangler` CLI for Cloudflare Workers + Pages.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CloudflareAdapter = void 0;
const child_process_1 = require("child_process");
const util_1 = require("util");
const child_process_2 = require("child_process");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const execFileP = (0, util_1.promisify)(child_process_2.execFile);
class CloudflareAdapter {
    name = 'cloudflare';
    async detect() {
        try {
            await execFileP('wrangler', ['--version'], { timeout: 5_000 });
            return true;
        }
        catch {
            return false;
        }
    }
    async preflight(opts) {
        const issues = [];
        const root = opts.cwd || process.cwd();
        const tomlPath = path.join(root, 'wrangler.toml');
        const jsoncPath = path.join(root, 'wrangler.jsonc');
        if (!fs.existsSync(tomlPath) && !fs.existsSync(jsoncPath)) {
            issues.push({
                severity: 'warning',
                message: 'no_wrangler_config',
                hint: 'Run `wrangler init` to create wrangler.toml',
            });
        }
        else {
            // Sanity-check wrangler.toml has a `name` entry (required for deploy).
            try {
                const src = fs.existsSync(tomlPath)
                    ? fs.readFileSync(tomlPath, 'utf-8')
                    : fs.readFileSync(jsoncPath, 'utf-8');
                if (!/^\s*name\s*=/m.test(src)) {
                    issues.push({
                        severity: 'error',
                        message: 'wrangler_missing_name',
                        hint: 'Add `name = "my-worker"` to wrangler.toml',
                    });
                }
            }
            catch (err) {
                issues.push({
                    severity: 'error',
                    message: `wrangler_config_invalid: ${err instanceof Error ? err.message : String(err)}`,
                });
            }
        }
        if (process.env.CI && !process.env.CLOUDFLARE_API_TOKEN) {
            issues.push({
                severity: 'warning',
                message: 'ci_without_token',
                hint: 'Set CLOUDFLARE_API_TOKEN env in CI for non-interactive deploy',
            });
        }
        const fatal = issues.some(i => i.severity === 'error');
        return { ok: !fatal, issues };
    }
    async deploy(opts) {
        const start = Date.now();
        const args = ['deploy'];
        if (opts.target)
            args.push('--name', opts.target);
        // Cloudflare doesn't have a "preview" build in the same sense; preview =
        // deploy to a versioned URL via `wrangler versions deploy` (Workers) OR
        // a branch preview (Pages). We default to standard deploy and let the
        // user pass --target for project differentiation.
        return new Promise((resolve) => {
            let stdout = '';
            let stderr = '';
            let timedOut = false;
            const timeout = opts.timeoutMs ?? 600_000;
            const child = (0, child_process_1.spawn)('wrangler', args, {
                cwd: opts.cwd || process.cwd(),
                env: process.env,
                stdio: ['ignore', 'pipe', 'pipe'],
            });
            const t = setTimeout(() => {
                timedOut = true;
                try {
                    child.kill('SIGTERM');
                }
                catch { /* */ }
            }, timeout);
            if (typeof t.unref === 'function')
                t.unref();
            child.stdout?.on('data', (c) => { stdout += String(c); });
            child.stderr?.on('data', (c) => { stderr += String(c); });
            child.on('exit', (code) => {
                clearTimeout(t);
                const exitCode = typeof code === 'number' ? code : -1;
                // Cloudflare prints multiple URLs: `https://<worker>.<account>.workers.dev`
                // and the main route URL. Pick the first.
                const urlMatch = (stdout + stderr).match(/https?:\/\/[a-zA-Z0-9.-]+\.(?:workers\.dev|pages\.dev)[^\s]*/);
                resolve({
                    ok: exitCode === 0 && !timedOut,
                    provider: this.name,
                    url: urlMatch ? urlMatch[0] : undefined,
                    durationMs: Date.now() - start,
                    exitCode,
                    error: timedOut ? `timeout_after_${timeout}ms` : (exitCode !== 0 ? `exit_${exitCode}: ${stderr.slice(0, 300)}` : undefined),
                });
            });
            child.on('error', (err) => {
                clearTimeout(t);
                resolve({
                    ok: false,
                    provider: this.name,
                    durationMs: Date.now() - start,
                    error: `spawn_error: ${err.message}`,
                });
            });
        });
    }
    /**
     * v1.19.0 — Cloudflare Workers alias swap via `wrangler versions deploy`.
     * Promotes a specific version id to take 100% of production traffic.
     * Falls back to a redeploy via `wrangler deploy` if no `from` is provided.
     */
    async promote(opts) {
        const start = Date.now();
        // Alias-swap path: `wrangler versions deploy <id>@100% --yes`.
        // Fallback (no source id): standard `wrangler deploy` against the
        // target environment via --env.
        const args = opts.from
            ? ['versions', 'deploy', `${opts.from}@100%`, '--yes', '--message', `openlife promote → ${opts.to}`]
            : ['deploy', '--env', opts.to];
        try {
            const { stdout, stderr } = await execFileP('wrangler', args, {
                cwd: opts.cwd || process.cwd(),
                timeout: opts.timeoutMs ?? 180_000,
            });
            const out = String(stdout) + String(stderr);
            const urlMatch = out.match(/https?:\/\/[a-zA-Z0-9.-]+\.(?:workers\.dev|pages\.dev)[^\s]*/);
            return {
                ok: true,
                provider: this.name,
                url: urlMatch ? urlMatch[0] : undefined,
                deploymentId: opts.from,
                durationMs: Date.now() - start,
                exitCode: 0,
            };
        }
        catch (err) {
            const e = err;
            return {
                ok: false,
                provider: this.name,
                durationMs: Date.now() - start,
                exitCode: typeof e.code === 'number' ? e.code : -1,
                error: `promote_failed: ${(e.stderr || e.message || '').slice(0, 300)}`,
            };
        }
    }
    async rollback(opts) {
        const start = Date.now();
        // `wrangler rollback` requires a deployment id. If not provided, wrangler
        // interactively prompts — we suppress that path by erroring with hint.
        if (!opts.to) {
            return {
                ok: false,
                provider: this.name,
                durationMs: 0,
                error: 'rollback_requires_id: pass --to <deployment-id>. List via `wrangler deployments list`.',
            };
        }
        const args = ['rollback', '--message', 'openlife-rollback', opts.to];
        try {
            const { stdout } = await execFileP('wrangler', args, {
                cwd: opts.cwd || process.cwd(),
                timeout: 120_000,
            });
            return {
                ok: true,
                provider: this.name,
                deploymentId: opts.to,
                url: String(stdout).split('\n').find(l => l.startsWith('https://')),
                durationMs: Date.now() - start,
                exitCode: 0,
            };
        }
        catch (err) {
            const e = err;
            return {
                ok: false,
                provider: this.name,
                durationMs: Date.now() - start,
                exitCode: typeof e.code === 'number' ? e.code : -1,
                error: `rollback_failed: ${(e.stderr || e.message || '').slice(0, 300)}`,
            };
        }
    }
}
exports.CloudflareAdapter = CloudflareAdapter;
