"use strict";
/**
 * UpgradeCommand — the open-core sales funnel for `openlife upgrade`.
 *
 * The Community CLI is a SHOWCASE + ORCHESTRATOR, never a runtime host for paid
 * code. This command:
 *   1. shows the paid tiers (read from TIER_FEATURES — single source of truth),
 *   2. opens openlife.online so the user can purchase,
 *   3. takes the license key + GitHub Packages token the checkout hands back,
 *   4. writes the token to ~/.npmrc (HOME, never the repo) and runs
 *      `npm i -g @openlife-business/cli`,
 *   5. delegates activation to the freshly installed `openlife-business` binary
 *      (so the paid runtime — with its own store/key — sees the license).
 *
 * No private code is imported here. Everything is process orchestration, exactly
 * like the existing `update --global` command. I/O, the browser launcher and the
 * command runner are injectable so the flow is unit-testable without touching
 * the network, the real ~/.npmrc, or a global npm install.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpgradeCommand = void 0;
const child_process_1 = require("child_process");
const LicenseManager_1 = require("../orchestrator/LicenseManager");
const WizardIO_1 = require("./install/WizardIO");
const openBrowser_1 = require("../util/openBrowser");
const npmrc_1 = require("../util/npmrc");
const SITE_PRICING = 'https://openlife.online/pricing';
const DEFAULT_REGISTRY = 'https://npm.pkg.github.com';
const SCOPE = '@openlife-business';
const BUSINESS_PKG = '@openlife-business/cli';
const BUSINESS_BIN = 'openlife-business';
/** Informational only — the site is the source of truth for billing. */
const PRICE_HINT = {
    pro: 'US$ 29/mês',
    team: 'US$ 199/mês',
    enterprise: 'a partir de US$ 2.000/mês',
};
class UpgradeCommand {
    deps;
    constructor(deps = {}) {
        this.deps = deps;
    }
    io() {
        return this.deps.io ?? new WizardIO_1.ReadlineWizardIO();
    }
    browser() {
        return this.deps.browser ?? openBrowser_1.openBrowser;
    }
    runner() {
        return (this.deps.runner ?? {
            run: (file, args) => {
                try {
                    (0, child_process_1.execFileSync)(file, args, { stdio: 'inherit' });
                    return { ok: true };
                }
                catch (e) {
                    return { ok: false, error: e.message };
                }
            },
        });
    }
    /** Human-readable tier table (used by interactive flow + `upgrade pricing`). */
    renderPricing() {
        const lines = ['OpenLife Business — planos pagos:', ''];
        for (const [tier, features] of Object.entries(LicenseManager_1.TIER_FEATURES)) {
            if (tier === 'community')
                continue;
            const hint = PRICE_HINT[tier] ? ` (${PRICE_HINT[tier]})` : '';
            lines.push(`${tier.toUpperCase()}${hint}`);
            for (const f of features)
                lines.push(`  • ${f}`);
            lines.push('');
        }
        lines.push(`Preços e compra em ${SITE_PRICING}`);
        return lines.join('\n');
    }
    /** Structured pricing for `--json`. */
    pricing() {
        return {
            ok: true,
            action: 'pricing',
            message: this.renderPricing(),
        };
    }
    /** Validate key + collect token; either via flags or interactive prompts. */
    async collectCredentials(io, opts) {
        let key = (opts.key || '').trim();
        if (!key)
            key = await io.text('Cole sua chave de licença (TIER-XXXX-XXXX-XXXX-XXXX)');
        const parsed = new LicenseManager_1.LicenseManager().parseKeyId(key);
        if (!parsed) {
            return {
                ok: false,
                result: {
                    ok: false,
                    action: 'upgrade',
                    message: 'Chave inválida. Esperado TIER-XXXX-XXXX-XXXX-XXXX (ex.: PRO-AB12-CD34-EF56-GH78).',
                },
            };
        }
        let token = (opts.token || '').trim();
        if (!token)
            token = (await io.secret('Cole o token de leitura do GitHub Packages (read:packages)')).trim();
        if (!token) {
            return {
                ok: false,
                result: {
                    ok: false,
                    action: 'upgrade',
                    message: 'Token vazio. Copie o token de acesso entregue no checkout de openlife.online.',
                },
            };
        }
        return { ok: true, key: parsed.raw, token, tier: parsed.tier };
    }
    /** Write ~/.npmrc, install the business package, delegate activation. */
    provision(io, key, token, tier, registry, opts) {
        const steps = [];
        const npmrc = (0, npmrc_1.upsertBusinessRegistry)({ scope: SCOPE, registry, token }, this.deps.npmrcPath);
        steps.push(npmrc.changed ? `~/.npmrc atualizado (${npmrc.path})` : '~/.npmrc já configurado');
        if (opts.install === false) {
            return {
                ok: true,
                action: 'upgrade',
                message: `Acesso configurado. Instale e ative manualmente:\n` +
                    `  npm i -g ${BUSINESS_PKG}\n` +
                    `  ${BUSINESS_BIN} license activate --key ${key}`,
                tier,
                registry,
                npmrcPath: npmrc.path,
                steps,
            };
        }
        io.print(`Instalando ${BUSINESS_PKG}…`);
        const install = this.runner().run('npm', ['install', '-g', BUSINESS_PKG]);
        if (!install.ok) {
            // Don't leave an orphan token behind if the install failed.
            (0, npmrc_1.removeBusinessRegistry)(SCOPE, this.deps.npmrcPath);
            steps.push(`falha no npm install — token removido do ~/.npmrc`);
            return {
                ok: false,
                action: 'upgrade',
                message: `Não foi possível instalar ${BUSINESS_PKG}: ${install.error}. Verifique o token e tente de novo.`,
                registry,
                steps,
            };
        }
        steps.push(`instalado ${BUSINESS_PKG}`);
        io.print('Ativando a licença…');
        const activate = this.runner().run(BUSINESS_BIN, ['license', 'activate', '--key', key]);
        if (!activate.ok) {
            steps.push('ativação automática falhou');
            return {
                ok: false,
                action: 'upgrade',
                message: `Instalado, mas a ativação automática falhou (${activate.error}). ` +
                    `Rode manualmente: ${BUSINESS_BIN} license activate --key ${key}`,
                tier,
                registry,
                npmrcPath: npmrc.path,
                steps,
            };
        }
        steps.push('licença ativada');
        return {
            ok: true,
            action: 'upgrade',
            message: `OpenLife Business ${tier.toUpperCase()} instalado e ativado. Rode "${BUSINESS_BIN} --help".`,
            tier,
            registry,
            npmrcPath: npmrc.path,
            steps,
        };
    }
    /** Full interactive funnel: pricing → browser → credentials → install → activate. */
    async run(opts = {}) {
        const io = this.io();
        const registry = (opts.registry || DEFAULT_REGISTRY).trim();
        try {
            io.header('OpenLife Business — Upgrade');
            io.print(this.renderPricing());
            if (opts.open !== false) {
                const opened = this.browser()(SITE_PRICING);
                if (opened)
                    io.hint(`Abrindo ${SITE_PRICING} no navegador…`);
                else
                    io.print(`Abra para comprar: ${SITE_PRICING}`);
                await io.pause('Conclua a compra e volte aqui. Enter para continuar');
            }
            const cred = await this.collectCredentials(io, opts);
            if (!cred.ok)
                return cred.result;
            let install = opts.install;
            if (install !== false && !opts.yes) {
                install = await io.yesNo(`Instalar ${BUSINESS_PKG} globalmente agora?`, true);
            }
            return this.provision(io, cred.key, cred.token, cred.tier, registry, { ...opts, install });
        }
        finally {
            io.close();
        }
    }
    /** Non-browser path: caller already purchased; just install + activate. */
    async install(opts = {}) {
        const io = this.io();
        const registry = (opts.registry || DEFAULT_REGISTRY).trim();
        try {
            const cred = await this.collectCredentials(io, opts);
            if (!cred.ok)
                return cred.result;
            return this.provision(io, cred.key, cred.token, cred.tier, registry, opts);
        }
        finally {
            io.close();
        }
    }
    /** Undo: remove the ~/.npmrc entry, uninstall the package, deactivate. */
    rollback() {
        const steps = [];
        const npmrc = (0, npmrc_1.removeBusinessRegistry)(SCOPE, this.deps.npmrcPath);
        steps.push(npmrc.changed ? `~/.npmrc limpo (${npmrc.path})` : '~/.npmrc já sem entrada business');
        const uninstall = this.runner().run('npm', ['uninstall', '-g', BUSINESS_PKG]);
        steps.push(uninstall.ok ? `desinstalado ${BUSINESS_PKG}` : `uninstall ignorado: ${uninstall.error}`);
        const deactivate = this.runner().run(BUSINESS_BIN, ['license', 'deactivate']);
        steps.push(deactivate.ok ? 'licença desativada' : 'deactivate ignorado (binário ausente)');
        return {
            ok: true,
            action: 'rollback',
            message: 'Rollback concluído. Voltou para OpenLife Community.',
            steps,
        };
    }
}
exports.UpgradeCommand = UpgradeCommand;
