/**
 * PdfService — renders a Pelagia PO export page to a real PDF via headless
 * Chromium (Playwright). Mirrors GstService/EpfoService: a tiny internal-only
 * Express proxy the Next app calls.
 *
 *   POST /pdf  { url }  →  application/pdf
 *
 * The app builds the PO export URL (its own /api/po/:id/export?format=pdf&pdf=1
 * carrying a short-lived service token) and posts it here; we navigate to it and
 * return the printed PDF bytes. The app then stores the PDF (R2) and emails the
 * vendor a download link (issue #14).
 *
 * Safety: this renders arbitrary URLs, so it is internal-only and guards against
 * SSRF by (a) requiring a shared token when PDF_SERVICE_TOKEN is set and
 * (b) only navigating to URLs whose origin matches ALLOWED_ORIGIN when set.
 */
import express from "express";
import { chromium, type Browser } from "playwright";

const PORT = Number(process.env.PORT ?? 3005);
const NAV_TIMEOUT_MS = Number(process.env.NAV_TIMEOUT_MS ?? 30_000);
const TOKEN = process.env.PDF_SERVICE_TOKEN ?? "";
const ALLOWED_ORIGIN = process.env.ALLOWED_ORIGIN ?? ""; // e.g. http://localhost:3000

function log(level: string, msg: string, ctx?: Record<string, unknown>) {
  const line = JSON.stringify({ ts: new Date().toISOString(), level, msg, ...ctx });
  (level === "ERROR" || level === "WARN" ? process.stderr : process.stdout).write(line + "\n");
}

// ── Browser (lazy singleton) ────────────────────────────────────────────────
let _browser: Browser | null = null;
async function getBrowser(): Promise<Browser> {
  if (_browser?.isConnected()) return _browser;
  _browser = await chromium.launch({ headless: true, args: ["--no-sandbox", "--disable-setuid-sandbox"] });
  _browser.on("disconnected", () => { _browser = null; });
  return _browser;
}

function originOf(url: string): string | null {
  try { return new URL(url).origin; } catch { return null; }
}

const app = express();
app.use(express.json({ limit: "1mb" }));

app.get("/health", (_req, res) => {
  res.json({ status: "ok", browser: _browser?.isConnected() ? "up" : "idle" });
});

app.post("/pdf", async (req, res) => {
  const started = Date.now();
  const { url } = (req.body ?? {}) as { url?: string };

  if (TOKEN && req.header("x-pdf-token") !== TOKEN) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  const origin = url ? originOf(url) : null;
  if (!url || !origin) return res.status(400).json({ error: "A valid url is required" });
  if (ALLOWED_ORIGIN && origin !== ALLOWED_ORIGIN) {
    return res.status(403).json({ error: "URL origin not allowed" });
  }

  let context;
  try {
    const browser = await getBrowser();
    context = await browser.newContext();
    const page = await context.newPage();
    await page.goto(url, { waitUntil: "networkidle", timeout: NAV_TIMEOUT_MS });
    const pdf = await page.pdf({ format: "A4", printBackground: true, preferCSSPageSize: true });
    res.setHeader("Content-Type", "application/pdf");
    res.send(pdf);
    log("INFO", "Rendered PDF", { origin, ms: Date.now() - started, bytes: pdf.length });
  } catch (e) {
    log("ERROR", "POST /pdf failed", { err: String(e) });
    res.status(502).json({ error: `PDF render failed: ${String(e)}` });
  } finally {
    await context?.close().catch(() => {});
  }
});

app.listen(PORT, () => log("INFO", "PdfService listening", { port: PORT, allowedOrigin: ALLOWED_ORIGIN || "(any)" }));
