import puppeteer from 'puppeteer';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { access, stat, readFile, writeFile, rename, unlink } from 'fs/promises';
import { execFile } from 'child_process';
import { promisify } from 'util';
import matter from 'gray-matter';

const execFileAsync = promisify(execFile);
const __dir = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dir, '..');
const inputPath  = resolve(root, 'output', 'book.html');
const rawPath    = resolve(root, 'output', 'kaleidoskop-raw.pdf');
const marksPath  = resolve(root, 'output', 'pdfmarks.ps');
const outputPath = resolve(root, 'output', 'kaleidoskop.pdf');

async function fileExists(path) {
  try { await access(path); return true; } catch { return false; }
}

// Encode a JS string as UTF-16BE hex for PostScript pdfmarks (handles umlauts etc.)
function toUtf16BeHex(str) {
  const hex = [];
  for (let i = 0; i < str.length; i++) {
    const cp = str.charCodeAt(i);
    hex.push(((cp >> 8) & 0xff).toString(16).padStart(2, '0'));
    hex.push((cp & 0xff).toString(16).padStart(2, '0'));
  }
  return 'FEFF' + hex.join('').toUpperCase();
}

function buildPdfmarks({ title, author, subject }) {
  return [
    '[ /Title <' + toUtf16BeHex(title)   + '>',
    '  /Author <' + toUtf16BeHex(author)  + '>',
    '  /Subject <' + toUtf16BeHex(subject) + '>',
    '  /Creator (Puppeteer + Ghostscript)',
    '  /Producer (kaleidoskop build pipeline)',
    '  /DOCINFO pdfmark',
  ].join('\n');
}

async function runGhostscript({ title, author, subject }) {
  const marks = buildPdfmarks({ title, author, subject });
  await writeFile(marksPath, marks, 'utf-8');

  const gs = 'gs';
  const args = [
    '-dBATCH', '-dNOPAUSE', '-dQUIET',
    '-sDEVICE=pdfwrite',
    '-dCompatibilityLevel=1.4',
    '-dPDFSETTINGS=/prepress',
    '-dEmbedAllFonts=true',
    '-dSubsetFonts=false',
    '-dDownsampleColorImages=false',
    '-dDownsampleGrayImages=false',
    '-dDownsampleMonoImages=false',
    `-sOutputFile=${outputPath}`,
    marksPath,
    rawPath,
  ];

  try {
    await execFileAsync(gs, args);
  } catch (err) {
    console.error('Ghostscript failed:', err.message);
    // Fall back to raw PDF so the build still produces output
    await rename(rawPath, outputPath);
    console.warn('Falling back to raw Puppeteer PDF (no GS post-processing).');
    return false;
  }
  return true;
}

async function generate() {
  try {
    await access(inputPath);
  } catch {
    console.error('output/book.html not found — run `pnpm build` first');
    process.exit(1);
  }

  // Read metadata from front-matter for PDF info dict
  const fmRaw = await readFile(resolve(root, 'content', '00-front-matter.md'), 'utf-8');
  const { data: fm } = matter(fmRaw);
  const title   = fm.title   || 'Das Kaleidoskop der Schlummerwelten';
  const author  = fm.author  || '';
  const subject = fm.subtitle || 'Kinderbuch';

  const systemChromium = '/usr/bin/chromium';
  const useSystem = await fileExists(systemChromium);

  console.log(`Launching Puppeteer (${useSystem ? 'system Chromium' : 'bundled Chrome'})…`);
  const browser = await puppeteer.launch({
    headless: true,
    ...(useSystem ? { executablePath: systemChromium } : {}),
  });
  const page = await browser.newPage();

  await page.goto(`file://${inputPath}`, { waitUntil: 'networkidle0' });

  // Write to temp file first so Ghostscript can read it
  await page.pdf({
    path: rawPath,
    width: '8.75in',
    height: '8.75in',
    printBackground: true,
    margin: { top: 0, bottom: 0, left: 0, right: 0 },
  });

  await browser.close();

  const rawSize = (await stat(rawPath)).size;
  console.log(`Raw PDF: ${(rawSize / 1_048_576).toFixed(1)} MB`);

  console.log('Running Ghostscript (font embedding + metadata)…');
  const gsOk = await runGhostscript({ title, author, subject });

  if (gsOk) {
    const finalSize = (await stat(outputPath)).size;
    console.log(`Final PDF: ${(finalSize / 1_048_576).toFixed(1)} MB`);
    await unlink(rawPath).catch(() => {});
    await unlink(marksPath).catch(() => {});
    console.log('PDF written to output/kaleidoskop.pdf (fonts embedded, metadata set)');
  }
}

generate().catch(err => { console.error(err); process.exit(1); });
