import { FONTS } from '../constants/fonts';

/**
 * Force-load every design-system font at app startup.
 *
 * Why this exists
 * ───────────────
 * `index.html` declares all fonts via the Google Fonts stylesheet with
 * `font-display: swap`. The `swap` directive tells the browser:
 * "render text in a fallback font immediately, then swap to the real
 * font once its woff2 file arrives." The CONSEQUENCE is that each
 * font's woff2 is only fetched when something on the page first
 * tries to render text in that family. Until then, the font is
 * *declared* (via @font-face) but not *available*.
 *
 * `measureTextWidth` (utils/textMetrics.js) uses the canvas 2D
 * `measureText` API. If the requested font isn't available, the
 * canvas context silently falls back to a system default font and
 * returns ITS metrics. That breaks any width-preservation math:
 * `fontSizeToPreserveWidth` computes the ratio between old-font
 * width and new-font width, but if the new font isn't loaded yet,
 * the "new-font width" is actually fallback-font width — usually
 * MUCH wider than a condensed face like Bebas Neue. The ratio is
 * wrong, the computed fontSize is wrong, and once the real font
 * arrives the text renders at the wrong size.
 *
 * Preloading every font upfront eliminates the race entirely: by
 * the time the user opens the Text tab and starts picking fonts,
 * the browser has all the woff2 files and `measureText` returns
 * real metrics.
 *
 * Cost: ~30KB × ~22 fonts = ~600KB total, fetched in parallel over
 * HTTP/2 and cached by the browser for subsequent sessions. Trivial
 * on broadband, tolerable on cellular. Runs in a post-paint
 * useEffect so it doesn't delay first paint.
 *
 * Integration with useFontsReady
 * ──────────────────────────────
 * `document.fonts.load()` adds each font to the document's
 * in-flight font set; `document.fonts.ready` doesn't resolve until
 * all in-flight fonts settle. So `useFontsReady`'s re-render
 * signal naturally waits for our preload to finish — out-of-bounds
 * measurements and other consumers of useFontsReady don't need any
 * special wiring.
 */
export async function preloadAllFonts() {
  if (typeof document === 'undefined' || !document.fonts) return;
  // Google Fonts serves a single woff2 file per family/weight/style.
  // The size in the spec string is only used to match @font-face
  // descriptors and doesn't affect which file gets fetched — 16px
  // matches every default declaration, so one load per family is
  // enough to make every size measurable.
  //
  // The family name is quoted so multi-word names (e.g. "Bebas
  // Neue", "Roboto Slab") parse as a single identifier rather than
  // two separate font names.
  const promises = FONTS.map((f) =>
    document.fonts.load(`16px "${f.family}"`).catch(() => null),
  );
  await Promise.all(promises);
}
