'use strict';
// Site icons + the Open Graph card for the public landing, drawn from the same
// design as ../../vk (the wooden Erudit tile: face «Э», score «8») and the app's
// board palette (ui/src/app.css). Everything is composed as SVG from the committed
// glyph outlines (build/extract.js -> glyphs.json), so no font is needed at build
// time; the PNG/ICO rasters are screenshots taken with the ui package's Playwright
// chromium (@playwright/test re-exports the browser API). Outputs go straight to
// ui/public/:
//   favicon.svg          96 viewBox, transparent, tile + «Э» (the score is illegible small)
//   favicon.ico          32x32 PNG-in-ICO render of the same
//   apple-touch-icon.png 180x180 opaque full-bleed tile (iOS masks its own corners)
//   og-image.png         1200x630 card: tile + wordmark on the board green
const fs = require('fs');
const path = require('path');

const G = JSON.parse(fs.readFileSync(path.join(__dirname, 'glyphs.json'), 'utf8'));
const UI = path.resolve(__dirname, '../../../ui');
const OUT = path.join(UI, 'public');

// ---- palette (vk loader tile + app.css board tokens) ------------------------
const FACE = '#D9B978', BORDER = '#B49559', GLYPH = '#1A1A1A';
const BOARD_DARK = '#2a3330', TEXT = '#e7ece8', TEXT_MUTED = '#cdd6cf';

// ---- glyph outlines -> SVG path data ----------------------------------------
const r2 = n => Math.round(n * 100) / 100;
// pathD renders one glyph's contours scaled by sc and translated by (tx, ty).
function pathD(g, sc, tx, ty) {
  const pt = (v, d) => `${r2(v[0] * sc + tx + d[0] * sc)} ${r2(v[1] * sc + ty + d[1] * sc)}`;
  const Z = [0, 0];
  return g.contours.map(ct => {
    const n = ct.v.length;
    let d = `M${pt(ct.v[0], Z)}`;
    for (let k = 1; k <= n; k++) {
      const a = k - 1, b = k % n;
      d += `C${pt(ct.v[a], ct.o[a])} ${pt(ct.v[b], ct.i[b])} ${pt(ct.v[b], Z)}`;
    }
    return d + 'Z';
  }).join('');
}
// glyphAt centres a glyph's bbox at (cx, cy) with the given pixel cap height, the
// same placement rule as the vk loader's glyph(). stroke fattens it slightly.
function glyphAt(ch, capPx, cx, cy, stroke, colour) {
  const g = G.glyphs[ch], sc = capPx / g.bbox.h;
  const d = pathD(g, sc, cx - (g.bbox.x + g.bbox.w / 2) * sc, cy - (g.bbox.y + g.bbox.h / 2) * sc);
  return `<path d="${d}" fill="${colour}" stroke="${colour}" stroke-width="${r2(stroke)}"/>`;
}
// textLine lays out a string on a baseline from the per-glyph advances; capPx sets
// the capital height (measured on «Э»). Returns the combined path + the width.
function textLine(str, capPx, x, y, colour) {
  const sc = capPx / G.glyphs['Э'].bbox.h;
  let d = '', w = 0;
  for (const ch of str) {
    const g = G.glyphs[ch];
    if (g.contours.length) d += pathD(g, sc, x + w, y);
    w += g.adv * sc;
  }
  return { svg: `<path d="${d}" fill="${colour}"/>`, width: w };
}
// tile draws the rounded wooden tile centred at (cx, cy): size px wide/high, with
// the vk loader's corner (6/52) and rim proportions, «Э» and optionally the «8».
function tile(cx, cy, size, withScore) {
  const h = size / 2, rx = size * (6 / 52), rim = size * (1.8 / 52);
  let s = `<rect x="${r2(cx - h + rim / 2)}" y="${r2(cy - h + rim / 2)}" width="${r2(size - rim)}" height="${r2(size - rim)}" rx="${r2(rx)}" fill="${FACE}" stroke="${BORDER}" stroke-width="${r2(rim)}"/>`;
  s += glyphAt('Э', size * (32 / 52), cx, cy - size * (1 / 52), size * (1 / 52), GLYPH);
  if (withScore) s += glyphAt('8', size * (8.5 / 52), cx + size * (19.5 / 52), cy + size * (18.5 / 52), size * (0.5 / 52), GLYPH);
  return s;
}
const svg = (w, h, body) => `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">${body}</svg>`;

// ---- favicon.svg (the committed vector master) -------------------------------
const favicon = svg(96, 96, tile(48, 48, 88, false)) + '\n';

// ---- apple-touch-icon: opaque full bleed, iOS applies its own corner mask ----
const appleTouch = svg(180, 180,
  `<rect width="180" height="180" fill="${FACE}"/>` +
  `<rect x="8" y="8" width="164" height="164" rx="18" fill="none" stroke="${BORDER}" stroke-width="4"/>` +
  glyphAt('Э', 100, 90, 88, 3, GLYPH) +
  glyphAt('8', 26, 146, 142, 1.5, GLYPH));

// ---- og-image: tile + wordmark, centred as one group on the board green ------
function ogImage() {
  const W = 1200, H = 630, tileSize = 340, gap = 84;
  const l1 = textLine('Эрудит', 112, 0, 0, TEXT);
  const l2 = textLine('Скрэббл — игра в слова', 44, 0, 0, TEXT_MUTED);
  const textW = Math.max(l1.width, l2.width);
  const left = (W - (tileSize + gap + textW)) / 2;
  const tx = left + tileSize + gap;
  // Two baselines around the vertical centre; the tile centre sits between them.
  const b1 = 295, b2 = 408;
  const body =
    `<rect width="${W}" height="${H}" fill="${BOARD_DARK}"/>` +
    tile(left + tileSize / 2, H / 2, tileSize, true) +
    textLine('Эрудит', 112, tx, b1, TEXT).svg +
    textLine('Скрэббл — игра в слова', 44, tx, b2, TEXT_MUTED).svg;
  console.log(`og-image: text ${Math.round(textW)}px wide, group left ${Math.round(left)}px`);
  return svg(W, H, body);
}

// ---- rasterisation (Playwright chromium from ui/node_modules) ----------------
async function shoot(page, markup, w, h, transparent) {
  await page.setViewportSize({ width: w, height: h });
  await page.setContent(`<body style="margin:0">${markup}</body>`);
  return page.screenshot({ omitBackground: transparent });
}
// icoFromPNG wraps one PNG as a single-entry .ico (ICONDIR + ICONDIRENTRY + PNG).
function icoFromPNG(png, sizePx) {
  const h = Buffer.alloc(22);
  h.writeUInt16LE(0, 0); h.writeUInt16LE(1, 2); h.writeUInt16LE(1, 4); // icon, 1 image
  h.writeUInt8(sizePx, 6); h.writeUInt8(sizePx, 7);                    // 32x32
  h.writeUInt16LE(1, 10); h.writeUInt16LE(32, 12);                     // planes, 32bpp
  h.writeUInt32LE(png.length, 14); h.writeUInt32LE(22, 18);            // size, offset
  return Buffer.concat([h, png]);
}

(async () => {
  fs.writeFileSync(path.join(OUT, 'favicon.svg'), favicon);
  const { chromium } = require(path.join(UI, 'node_modules', '@playwright/test'));
  const browser = await chromium.launch();
  const page = await browser.newPage();
  const fav32 = await shoot(page, svg(32, 32, tile(16, 16, 29.33, false)), 32, 32, true);
  fs.writeFileSync(path.join(OUT, 'favicon.ico'), icoFromPNG(fav32, 32));
  fs.writeFileSync(path.join(OUT, 'apple-touch-icon.png'), await shoot(page, appleTouch, 180, 180, false));
  fs.writeFileSync(path.join(OUT, 'og-image.png'), await shoot(page, ogImage(), 1200, 630, false));
  await browser.close();
  for (const f of ['favicon.svg', 'favicon.ico', 'apple-touch-icon.png', 'og-image.png']) {
    console.log('wrote', path.join(OUT, f), fs.statSync(path.join(OUT, f)).size, 'bytes');
  }
})();
