"use strict";
/**
 * LicenseCommand — thin CLI surface for `openlife license`.
 *
 *   openlife license activate --key PRO-XXXX-XXXX-XXXX-XXXX   (online exchange)
 *   openlife license activate --token ./license-token.json   (offline / air-gapped)
 *   openlife license status
 *   openlife license deactivate
 *
 * Activation has two paths:
 *   - `--key`   : exchange the short key-id with the license server (private
 *                 repo) for a signed token, then verify + cache it. The server
 *                 URL comes from OPENLIFE_LICENSE_SERVER; absent until the
 *                 private repo is deployed, so this path reports a clear message.
 *   - `--token` : load a pre-issued signed token from disk (Enterprise / no-net
 *                 install), verify it the same way, and cache it.
 *
 * Every path returns a `{ ok }` shape for the CLI's printCliResult helper.
 */
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.LicenseCommand = void 0;
const fs = __importStar(require("fs"));
const LicenseManager_1 = require("../orchestrator/LicenseManager");
const LicenseStore_1 = require("../orchestrator/LicenseStore");
const Entitlements_1 = require("../orchestrator/Entitlements");
class LicenseCommand {
    root;
    manager;
    store;
    entitlements;
    constructor(root = process.cwd(), manager) {
        this.root = root;
        this.manager = manager || new LicenseManager_1.LicenseManager();
        this.store = new LicenseStore_1.LicenseStore(root);
        this.entitlements = new Entitlements_1.Entitlements(root, this.manager);
    }
    /** Common verify + persist step for both activation paths. */
    acceptToken(token, action) {
        const verdict = this.manager.verifyToken(token);
        if (!verdict.valid) {
            return { ok: false, action, message: `License rejected: ${verdict.reason}.` };
        }
        if (!this.manager.isCurrent(token)) {
            return { ok: false, action, message: 'License token has expired. Renew it and try again.' };
        }
        this.store.save(token, 'activate');
        return {
            ok: true,
            action,
            message: `OpenLife Business activated — ${token.payload.tier.toUpperCase()} tier.`,
            tier: token.payload.tier,
            features: this.manager.entitlements(token),
            expiresAt: token.payload.expiresAt,
        };
    }
    /** Activate from a pre-issued signed token file (offline path). */
    activateFromTokenFile(tokenPath) {
        if (!fs.existsSync(tokenPath)) {
            return { ok: false, action: 'activate', message: `Token file not found: ${tokenPath}` };
        }
        let token;
        try {
            token = JSON.parse(fs.readFileSync(tokenPath, 'utf-8'));
        }
        catch (e) {
            return { ok: false, action: 'activate', message: `Could not parse token file: ${e.message}` };
        }
        return this.acceptToken(token, 'activate');
    }
    /** Activate by exchanging a key-id with the license server (online path). */
    async activateFromKey(keyId) {
        const parsed = this.manager.parseKeyId(keyId);
        if (!parsed) {
            return {
                ok: false,
                action: 'activate',
                message: 'Invalid key format. Expected TIER-XXXX-XXXX-XXXX-XXXX (e.g. PRO-AB12-CD34-EF56-GH78).',
            };
        }
        const server = process.env.OPENLIFE_LICENSE_SERVER;
        if (!server) {
            return {
                ok: false,
                action: 'activate',
                message: 'Online activation server not configured (OPENLIFE_LICENSE_SERVER unset). ' +
                    'Use the offline path meanwhile: openlife license activate --token <file>.',
            };
        }
        let token;
        try {
            const res = await fetch(`${server.replace(/\/$/, '')}/v1/activate`, {
                method: 'POST',
                headers: { 'content-type': 'application/json' },
                body: JSON.stringify({ keyId: parsed.raw }),
            });
            if (!res.ok) {
                return { ok: false, action: 'activate', message: `Activation server returned ${res.status}.` };
            }
            token = (await res.json());
        }
        catch (e) {
            return { ok: false, action: 'activate', message: `Could not reach activation server: ${e.message}` };
        }
        return this.acceptToken(token, 'activate');
    }
    /** Report the current entitlement state. */
    status(now = new Date()) {
        const st = this.entitlements.state(now);
        let daysRemaining = null;
        if (st.expiresAt) {
            const ms = Date.parse(st.expiresAt) - now.getTime();
            daysRemaining = Number.isNaN(ms) ? null : Math.floor(ms / 86_400_000);
        }
        const message = st.status === 'active'
            ? `Active — ${st.tier.toUpperCase()} tier, ${daysRemaining ?? '?'} day(s) remaining.`
            : st.status === 'expired'
                ? 'License expired. Renew, then re-run activate.'
                : st.status === 'invalid'
                    ? 'Cached license failed verification. Re-activate with a valid key.'
                    : 'No license — running OpenLife Community (free, fully functional).';
        return {
            ok: st.status === 'active' || st.status === 'none',
            action: 'status',
            message,
            tier: st.tier,
            features: st.features,
            expiresAt: st.expiresAt,
            daysRemaining,
            status: st.status,
        };
    }
    /** Remove the cached license; revert to Community. */
    deactivate() {
        this.store.clear('user-requested deactivate');
        return { ok: true, action: 'deactivate', message: 'License removed. Reverted to OpenLife Community.' };
    }
}
exports.LicenseCommand = LicenseCommand;
