/**
 * src/security/license-routes.ts
 *
 * HTTP surface for the license module:
 *   GET  /api/license/status   — current state (used by dashboard banner)
 *   POST /api/license/activate — activate a key, persist signed license
 *   POST /api/license/heartbeat — manual heartbeat refresh
 *   POST /api/license/deactivate — clear license file (user-initiated)
 *
 * All endpoints require the local owner token (authMiddleware) — the
 * license gate is loopback-only by design; remote attackers can't reach
 * it without first cracking the device's owner.token file.
 */
import { z } from 'zod';
import { authMiddleware } from '../auth/middleware.js';
import { createChildLogger } from '../utils/logger.js';
import { getDataDir } from '../utils/data-dir.js';
import { getLicenseStatus, getMachineFingerprint, getStoredFingerprint, activateLicense, heartbeat, storeSignedLicense, loadAndVerifyLicense, } from './license.js';
import { existsSync, unlinkSync } from 'node:fs';
import { join } from 'node:path';
const log = createChildLogger('license:routes');
const activateBody = z.object({
    license_key: z.string().min(8).max(128),
});
export async function registerLicenseRoutes(app) {
    app.get('/api/license/status', { preHandler: [authMiddleware] }, async (_req, reply) => {
        const status = getLicenseStatus(getDataDir());
        reply.send(status);
    });
    app.post('/api/license/activate', { preHandler: [authMiddleware] }, async (req, reply) => {
        const parsed = activateBody.safeParse(req.body);
        if (!parsed.success) {
            return reply.status(400).send({ ok: false, error: parsed.error.flatten() });
        }
        try {
            const fp = getMachineFingerprint();
            // Use the stable stored fingerprint from machine.fp so re-activation
            // on the same install survives hostname/CPU-string drift. First
            // run still works because getStoredFingerprint writes a fresh one.
            fp.fingerprint = getStoredFingerprint(getDataDir());
            const signed = await activateLicense(parsed.data.license_key, fp);
            storeSignedLicense(getDataDir(), signed);
            log.info({ key_last4: signed.key.slice(-4) }, 'license activated');
            reply.send({ ok: true, status: getLicenseStatus(getDataDir()) });
        }
        catch (err) {
            log.warn({ error: err.message }, 'license activation failed');
            reply.status(400).send({ ok: false, error: err.message });
        }
    });
    app.post('/api/license/heartbeat', { preHandler: [authMiddleware] }, async (_req, reply) => {
        const license = loadAndVerifyLicense(getDataDir());
        if (!license) {
            return reply.status(400).send({ ok: false, error: 'No license on file' });
        }
        try {
            const refreshed = await heartbeat(license);
            storeSignedLicense(getDataDir(), refreshed);
            reply.send({ ok: true, status: getLicenseStatus(getDataDir()) });
        }
        catch (err) {
            log.warn({ error: err.message }, 'heartbeat failed');
            reply.status(502).send({ ok: false, error: err.message });
        }
    });
    app.post('/api/license/deactivate', { preHandler: [authMiddleware] }, async (_req, reply) => {
        const path = join(getDataDir(), 'license.bin');
        if (existsSync(path))
            unlinkSync(path);
        reply.send({ ok: true });
    });
}
//# sourceMappingURL=license-routes.js.map