import puppeteer from 'puppeteer';
import { resolve, basename, dirname, extname } from 'path';
import { existsSync, mkdirSync } from 'fs';
import { fileURLToPath } from 'url';
import { createServer } from 'http';
import { readFile } from 'fs/promises';

const __dirname = dirname(fileURLToPath(import.meta.url));
const PROJECT_ROOT = resolve(__dirname, '..');
const OUTPUT_DIR = resolve(PROJECT_ROOT, 'output/pdf');

const MIME_TYPES = {
  '.html': 'text/html',
  '.css': 'text/css',
  '.js': 'application/javascript',
  '.mjs': 'application/javascript',
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.webp': 'image/webp',
  '.svg': 'image/svg+xml',
  '.json': 'application/json',
  '.woff': 'font/woff',
  '.woff2': 'font/woff2',
  '.ttf': 'font/ttf',
};

async function generatePdf(htmlPath, outDirOverride) {
  const absolutePath = resolve(htmlPath);
  if (!existsSync(absolutePath)) {
    console.error(`File not found: ${absolutePath}`);
    process.exit(1);
  }

  const outDir = outDirOverride ? resolve(outDirOverride) : OUTPUT_DIR;
  mkdirSync(outDir, { recursive: true });

  const pdfName = basename(absolutePath, '.html') + '.pdf';
  const pdfPath = resolve(outDir, pdfName);

  // Serve the project root so the HTML can load /templates/cv-style.css and any other assets.
  const server = createServer(async (req, res) => {
    const filePath = resolve(
      PROJECT_ROOT,
      decodeURIComponent(req.url).replace(/^\//, ''),
    );
    try {
      const data = await readFile(filePath);
      const ext = extname(filePath);
      res.writeHead(200, {
        'Content-Type': MIME_TYPES[ext] || 'application/octet-stream',
      });
      res.end(data);
    } catch {
      res.writeHead(404);
      res.end('Not found');
    }
  });

  await new Promise((r) => server.listen(0, '127.0.0.1', r));
  const port = server.address().port;
  const relPath = absolutePath.replace(PROJECT_ROOT + '/', '');

  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox'],
  });
  const page = await browser.newPage();

  await page.goto(`http://127.0.0.1:${port}/${relPath}`, {
    waitUntil: 'networkidle0',
    timeout: 30000,
  });

  // Wait for web fonts (if any) to be ready before rasterizing.
  await page.evaluate(async () => {
    if (document.fonts && document.fonts.ready) {
      await document.fonts.ready;
    }
  });

  await page.pdf({
    path: pdfPath,
    format: 'A4',
    printBackground: true,
    margin: { top: 0, right: 0, bottom: 0, left: 0 },
    preferCSSPageSize: true,
  });

  await browser.close();
  server.close();
  console.log(`PDF generated: ${pdfPath}`);
  return pdfPath;
}

const args = process.argv.slice(2);
if (args.length === 0) {
  console.error('Usage: node generate-pdf.mjs <html-file> [out-dir]');
  process.exit(1);
}

const [htmlFile, outDir] = args;
generatePdf(htmlFile, outDir);
