/**
 * Render the social card and icon set to PNG.
 *
 *   node apps/web/tools/render-assets.mjs
 *
 * Generated rather than hand-drawn so that the mark, the wordmark and the
 * tagline cannot drift apart from the product, and so regenerating after a
 * brand change is one command.
 *
 * Uses the system Chrome via `channel: 'chrome'` rather than Playwright's own
 * bundled browser, so `npm install` does not pull a ~150MB download for a
 * script that runs occasionally, by hand, when the brand changes.
 */
import { chromium } from 'playwright';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const here = dirname(fileURLToPath(import.meta.url));
const publicDir = join(here, '..', 'public');

const PIG_SVG = `
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
  <path d="M7.4 8.6 5.1 3.9c-.2-.5.3-1 .8-.8l5.2 2.2z" fill="INK"/>
  <path d="M24.6 8.6 26.9 3.9c.2-.5-.3-1-.8-.8l-5.2 2.2z" fill="INK"/>
  <path d="M16 5.2c6.3 0 11.2 4.3 11.2 10.4 0 6.5-5 11.2-11.2 11.2S4.8 22.1 4.8 15.6C4.8 9.5 9.7 5.2 16 5.2z" fill="INK"/>
  <ellipse cx="11.6" cy="13.4" rx="1.5" ry="1.8" fill="PAPER"/>
  <ellipse cx="20.4" cy="13.4" rx="1.5" ry="1.8" fill="PAPER"/>
  <rect x="11.3" y="17.6" width="9.4" height="6.2" rx="3.1" fill="PAPER"/>
  <ellipse cx="14.2" cy="20.7" rx="1.15" ry="1.5" fill="INK"/>
  <ellipse cx="17.8" cy="20.7" rx="1.15" ry="1.5" fill="INK"/>
</svg>`;

const icon = (ink, paper) => PIG_SVG.replaceAll('INK', ink).replaceAll('PAPER', paper);

/**
 * An icon page with padding around the mark.
 *
 * Home-screen and maskable icons are cropped by the platform — iOS rounds the
 * corners, Android may apply a circle. A mark drawn edge to edge loses its
 * ears to that crop, so it is inset inside a filled plate.
 */
function iconPage({ size, inset, background, ink, radius = 0 }) {
  return `<!doctype html><html><head><meta charset="utf-8"><style>
    *{margin:0;padding:0;box-sizing:border-box}
    body{width:${size}px;height:${size}px;display:flex;align-items:center;justify-content:center;
         background:${background};border-radius:${radius}px;overflow:hidden}
    svg{width:${size - inset * 2}px;height:${size - inset * 2}px}
  </style></head><body>${icon(ink, background)}</body></html>`;
}

const browser = await chromium.launch({ channel: 'chrome' });

async function shoot(html, path, width, height, scale = 1) {
  const ctx = await browser.newContext({
    viewport: { width, height },
    deviceScaleFactor: scale,
  });
  const page = await ctx.newPage();
  await page.setContent(html, { waitUntil: 'networkidle' });
  await page.screenshot({ path, omitBackground: false });
  await ctx.close();
  console.log(`  ${path.replace(publicDir + '/', '')}  ${width * scale}×${height * scale}`);
}

console.log('Rendering assets…');

// Social card. Rendered at 1× because 1200×630 is already the target size —
// unfurlers do not use a 2× variant and the extra bytes cost load time.
const { readFile } = await import('node:fs/promises');
const ogHtml = await readFile(join(here, 'og-template.html'), 'utf8');
await shoot(ogHtml, join(publicDir, 'og.png'), 1200, 630, 1);

// Apple touch icon. iOS composites onto whatever it likes and rounds the
// corners itself, so this is drawn on an opaque white plate with generous
// inset — a transparent one renders black on some home screens.
await shoot(
  iconPage({ size: 180, inset: 26, background: '#ffffff', ink: '#09090b' }),
  join(publicDir, 'apple-touch-icon.png'),
  180,
  180,
);

// PWA icons. `maskable` gets a larger inset so the safe zone survives a
// circular mask on Android.
await shoot(
  iconPage({ size: 192, inset: 24, background: '#ffffff', ink: '#09090b' }),
  join(publicDir, 'icon-192.png'),
  192,
  192,
);
await shoot(
  iconPage({ size: 512, inset: 64, background: '#ffffff', ink: '#09090b' }),
  join(publicDir, 'icon-512.png'),
  512,
  512,
);
await shoot(
  iconPage({ size: 512, inset: 112, background: '#ffffff', ink: '#09090b' }),
  join(publicDir, 'icon-maskable-512.png'),
  512,
  512,
);

// No separate tiny favicon is rendered. Chrome hangs screenshotting viewports
// below roughly 128px, and it is unnecessary: browsers prefer the SVG, and
// icon-192 downscales cleanly for the ones that do not.

await browser.close();
console.log('Done.');
