/* ============================================================
 * Copyright (c) 2026 RAVAPI Soluções. www.ravapi.com
 * Geração de PDF
 *
 * O template é função pura e testada; isto aqui é o adaptador que leva
 * o HTML ao Chromium. Fica atrás de uma interface para o domínio não
 * depender do Puppeteer e para o teste conseguir substituir.
 *
 * ATENÇÃO: PuppeteerPdf não tem teste automatizado — exige Chromium.
 * O que ele produz (o HTML) é que está coberto.
 * ============================================================ */

export interface GeradorPdf {
  gerar(html: string): Promise<Buffer>;
}

export interface OpcoesPuppeteer {
  /** Instância já criada pela aplicação. Abrir um browser por PDF é caro. */
  browser: {
    newPage(): Promise<{
      setContent(html: string, o?: unknown): Promise<void>;
      pdf(o?: unknown): Promise<Buffer | Uint8Array>;
      close(): Promise<void>;
    }>;
  };
  /** Tempo máximo de renderização. */
  timeoutMs?: number;
}

export class PuppeteerPdf implements GeradorPdf {
  constructor(private readonly opcoes: OpcoesPuppeteer) {}

  async gerar(html: string): Promise<Buffer> {
    const pagina = await this.opcoes.browser.newPage();
    try {
      // networkidle0 garante que as fontes web carregaram antes de imprimir.
      // Sem isso o PDF sai com a fonte de fallback de vez em quando — e o
      // recibo fica com aparência diferente conforme o dia.
      await pagina.setContent(html, {
        waitUntil: 'networkidle0',
        timeout: this.opcoes.timeoutMs ?? 15_000,
      });
      const saida = await pagina.pdf({
        format: 'A4',
        printBackground: true,     // sem isto a tarja de CANCELADO some
        preferCSSPageSize: true,   // respeita o @page do template
        margin: { top: '10mm', right: '10mm', bottom: '10mm', left: '10mm' },
      });
      return Buffer.isBuffer(saida) ? saida : Buffer.from(saida);
    } finally {
      await pagina.close();
    }
  }
}
