// Rasterize a feed thumbnail SVG to PNG so every published page has a guaranteed
// raster og:image (WeChat / browsers don't render SVG cover images).
//
// PNGs are derived lazily from the sibling `<base>.thumbnail.svg` and cached on disk
// as `<base>.thumbnail.png`. Regenerated when the SVG is newer than the cached PNG.
import fs from 'node:fs';
import { Resvg } from '@resvg/resvg-js';

const RENDER_WIDTH = 540; // matches the 540x720 feed card aspect

/** SVG → PNG buffer. White background avoids black fills where clients ignore alpha. */
export function rasterizeThumbnailSvgToPng(svg) {
  const resvg = new Resvg(svg, {
    background: 'white',
    fitTo: { mode: 'width', value: RENDER_WIDTH },
    font: { loadSystemFonts: true }, // CJK + serif via the host font stack (PingFang/Georgia on macOS)
  });
  return resvg.render().asPng();
}

/** Absolute path of the PNG that mirrors a `.thumbnail.svg`. */
export function thumbnailPngPathForSvg(svgAbsPath) {
  return svgAbsPath.replace(/\.svg$/i, '.png');
}

/**
 * Ensure a `.thumbnail.png` exists and is at least as fresh as its `.thumbnail.svg`.
 * @returns {string|null} the PNG path, or null when no source SVG is available.
 */
export function ensureThumbnailPng(svgAbsPath) {
  if (!fs.existsSync(svgAbsPath)) return null;
  const pngPath = thumbnailPngPathForSvg(svgAbsPath);
  try {
    const svgStat = fs.statSync(svgAbsPath);
    if (fs.existsSync(pngPath) && fs.statSync(pngPath).mtimeMs >= svgStat.mtimeMs) {
      return pngPath;
    }
    const svg = fs.readFileSync(svgAbsPath, 'utf8');
    fs.writeFileSync(pngPath, rasterizeThumbnailSvgToPng(svg));
    return pngPath;
  } catch {
    // If rasterization fails, fall back to an existing PNG if present, else give up.
    return fs.existsSync(pngPath) ? pngPath : null;
  }
}
