import { createServer } from 'node:http';
import { readFile, readdir } from 'node:fs/promises';
import { extname, join } from 'node:path';
import { chromium } from 'playwright';
import type { ProcessState } from '../src/tools/mapper/core';

/** Serve only the compiled renderer and licensed font on one ephemeral loopback port. */
export async function renderLocalProcess(state: ProcessState, format: 'svg' | 'png' | 'pdf', projectRoot: string): Promise<Uint8Array> {
  const directory = join(projectRoot, 'dist', 'render');
  const assets = new Map<string, { data: Uint8Array | string; type: string }>();
  for (const entry of await readdir(directory, { withFileTypes: true })) {
    if (entry.isFile() && ['.js', '.css', '.wasm'].includes(extname(entry.name))) assets.set(`/${entry.name}`, { data: await readFile(join(directory, entry.name)), type: entry.name.endsWith('.js') ? 'text/javascript' : entry.name.endsWith('.css') ? 'text/css' : 'application/wasm' });
  }
  assets.set('/tools-assets/fonts/NotoSans-Regular.ttf', { data: await readFile(join(projectRoot, 'public', 'tools-assets', 'fonts', 'NotoSans-Regular.ttf')), type: 'font/ttf' });
  assets.set('/', { data: '<!doctype html><html lang="en"><head><meta charset="UTF-8"><title>Local process renderer</title></head><body><main id="stage"></main><script type="module" src="/renderer.js"></script></body></html>', type: 'text/html;charset=utf-8' });
  const server = createServer((request, response) => {
    const resource = request.method === 'GET' ? assets.get(request.url ?? '') : undefined;
    response.setHeader('Cache-Control', 'no-store');
    response.setHeader('Referrer-Policy', 'no-referrer');
    response.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self'; connect-src 'self'; img-src 'self' blob: data:; font-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'");
    if (!resource) { response.writeHead(404); response.end('Not found'); return; }
    response.writeHead(200, { 'Content-Type': resource.type }); response.end(resource.data);
  });
  await new Promise<void>((resolve, reject) => { server.once('error', reject); server.listen(0, '127.0.0.1', resolve); });
  let browser: Awaited<ReturnType<typeof chromium.launch>> | undefined;
  try {
    const address = server.address();
    if (!address || typeof address === 'string') throw new Error('Could not start the local renderer.');
    const origin = `http://127.0.0.1:${address.port}`;
    browser = await chromium.launch({ headless: true });
    const context = await browser.newContext({ viewport: { width: 1600, height: 1200 }, serviceWorkers: 'block' });
    const blocked: string[] = [];
    await context.route('**/*', route => {
      const url = route.request().url();
      if (url.startsWith(`${origin}/`)) return route.continue();
      blocked.push('external_request'); return route.abort();
    });
    const page = await context.newPage();
    page.setDefaultTimeout(30_000);
    await page.goto(origin);
    await page.waitForFunction(() => typeof window.essentialRender === 'function');
    const result = await page.evaluate(async ({ state, format }) => window.essentialRender(state, format), { state, format });
    if (blocked.length) throw new Error('The renderer attempted a blocked non-local request.');
    return new Uint8Array(result.data);
  } finally {
    await browser?.close();
    await new Promise<void>((resolve, reject) => server.close(error => error ? reject(error) : resolve()));
  }
}
