/*
 * Um PDF com uma foto por folha (o "Baixar em PDF" do editor de artes): cada
 * folha é a foto JPEG da página inteira, esticada no tamanho da folha em
 * pontos (1/72 de polegada). Escrito à mão (o formato é pequeno): catálogo,
 * lista de folhas e, por folha, a folha, o desenho ("põe a foto na folha
 * inteira") e a foto (DCTDecode = o próprio JPEG dentro do PDF, sem recomprimir).
 * O JPEG precisa ser RGB de linha única (não progressivo).
 */

export type FolhaDeFoto = {
  jpeg: Buffer;
  /* Pixels da foto. */
  largura: number;
  altura: number;
  /* Tamanho da folha, em pontos. */
  larguraPt: number;
  alturaPt: number;
};

const n = (v: number) => String(Math.round(v * 1000) / 1000);

export function pdfDeFotos(folhas: FolhaDeFoto[]): Buffer {
  const partes: Buffer[] = [];
  const posicoes: number[] = [];
  let tamanho = 0;
  const escrever = (pedaco: string | Buffer) => {
    const b = typeof pedaco === "string" ? Buffer.from(pedaco, "latin1") : pedaco;
    partes.push(b);
    tamanho += b.length;
  };
  const objeto = (numero: number, corpo: string | Buffer[]) => {
    posicoes[numero] = tamanho;
    escrever(`${numero} 0 obj\n`);
    if (typeof corpo === "string") escrever(corpo);
    else for (const b of corpo) escrever(b);
    escrever("\nendobj\n");
  };

  /* 1 = catálogo, 2 = lista de folhas; cada folha usa três números a partir do 3. */
  const folha = (i: number) => 3 + i * 3;
  escrever("%PDF-1.4\n%\xE2\xE3\xCF\xD3\n");
  objeto(1, "<< /Type /Catalog /Pages 2 0 R >>");
  objeto(2, `<< /Type /Pages /Count ${folhas.length} /Kids [${folhas.map((_, i) => `${folha(i)} 0 R`).join(" ")}] >>`);
  folhas.forEach((f, i) => {
    const [numFolha, numDesenho, numFoto] = [folha(i), folha(i) + 1, folha(i) + 2];
    objeto(numFolha, `<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${n(f.larguraPt)} ${n(f.alturaPt)}] /Resources << /XObject << /Foto ${numFoto} 0 R >> >> /Contents ${numDesenho} 0 R >>`);
    const desenho = `q ${n(f.larguraPt)} 0 0 ${n(f.alturaPt)} 0 0 cm /Foto Do Q`;
    objeto(numDesenho, `<< /Length ${desenho.length} >>\nstream\n${desenho}\nendstream`);
    objeto(numFoto, [
      Buffer.from(`<< /Type /XObject /Subtype /Image /Width ${Math.round(f.largura)} /Height ${Math.round(f.altura)} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${f.jpeg.length} >>\nstream\n`, "latin1"),
      f.jpeg,
      Buffer.from("\nendstream", "latin1"),
    ]);
  });

  const total = 3 + folhas.length * 3;
  const inicioDaTabela = tamanho;
  escrever(`xref\n0 ${total}\n0000000000 65535 f \n`);
  for (let i = 1; i < total; i++) escrever(`${String(posicoes[i]).padStart(10, "0")} 00000 n \n`);
  escrever(`trailer\n<< /Size ${total} /Root 1 0 R >>\nstartxref\n${inicioDaTabela}\n%%EOF\n`);
  return Buffer.concat(partes);
}
