import { tw4FontVars } from "#og-image-virtual/tw4-theme.mjs";
import compatibility from "#og-image/compatibility";
import { defu } from "defu";
import { useOgImageRuntimeConfig } from "../../utils.js";
import { extractCodepoints, getDefaultFontFamily, loadAllFontsDebug, loadFontsForRenderer } from "../fonts.js";
import { getResvg, getSatori, getSharp } from "./instances.js";
import { createVNodes } from "./vnodes.js";
const _satoriFontCache = /* @__PURE__ */ new WeakMap();
const RE_SATORI_WARN_PREFIX = /^\s*WARN\s*/;
const RE_FONT_QUOTES = /^['"]|['"]$/g;
const RE_ALPHA_CHAR = /[a-z]/i;
function withWarningCapture(fn) {
  const warnings = [];
  const originalWarn = console.warn;
  console.warn = (...args) => {
    const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
    if (msg.includes("WARN") || msg.includes("not supported") || msg.includes("Expected style"))
      warnings.push(msg.replace(RE_SATORI_WARN_PREFIX, ""));
    originalWarn.apply(console, args);
  };
  return fn().then((result) => ({ result, warnings })).finally(() => {
    console.warn = originalWarn;
  });
}
export async function createSvg(event) {
  const { options } = event;
  const { satoriOptions: _satoriOptions } = useOgImageRuntimeConfig();
  const { fontFamilyOverride, defaultFont } = getDefaultFontFamily(options);
  const [satori, vnodes] = await Promise.all([
    getSatori(),
    createVNodes(event)
  ]);
  const codepoints = extractCodepoints(vnodes);
  const hasCustomFonts = Array.isArray(options.fonts) && options.fonts.length > 0;
  const fonts = await loadFontsForRenderer(event, {
    supportedFormats: /* @__PURE__ */ new Set(["ttf", "otf", "woff"]),
    component: options.component,
    fontFamilyOverride: fontFamilyOverride || defaultFont,
    codepoints,
    fontDefs: options.fonts
  });
  await event._nitro.hooks.callHook("nuxt-og-image:satori:vnodes", vnodes, event);
  const satoriFonts = !hasCustomFonts && _satoriFontCache.get(fonts) || fonts.map((f) => ({ ...f, name: f.family }));
  if (!hasCustomFonts)
    _satoriFontCache.set(fonts, satoriFonts);
  const loadedFamilies = new Set(satoriFonts.map((f) => f.name));
  const defaultFamily = satoriFonts[0]?.name;
  function resolveAvailableFamily(cssValue) {
    const families = cssValue.split(",").map((f) => f.trim().replace(RE_FONT_QUOTES, ""));
    const available = families.filter((f) => loadedFamilies.has(f));
    if (available.length > 0)
      return available.join(", ");
    return defaultFamily;
  }
  const fontFamily = {};
  for (const [key, val] of Object.entries(tw4FontVars)) {
    if (!key.startsWith("font-") || !val || !RE_ALPHA_CHAR.test(val))
      continue;
    const slot = key.slice(5);
    const resolved = resolveAvailableFamily(val);
    if (resolved)
      fontFamily[slot] = resolved;
  }
  const satoriOptions = defu(options.satori, _satoriOptions, {
    fonts: satoriFonts,
    tailwindConfig: Object.keys(fontFamily).length ? { theme: { fontFamily } } : void 0,
    embedFont: true,
    width: options.width,
    height: options.height
  });
  const { result, warnings } = await withWarningCapture(
    () => satori(vnodes, satoriOptions)
  );
  return { svg: result, warnings, fonts };
}
async function createPng(event) {
  const { resvgOptions } = useOgImageRuntimeConfig();
  const { svg } = await createSvg(event);
  if (!svg)
    throw new Error("Failed to create SVG");
  const options = defu(event.options.resvg, resvgOptions);
  const Resvg = await getResvg();
  const resvg = new Resvg(svg, options);
  const pngData = resvg.render();
  const png = pngData.asPng();
  if (typeof pngData.free === "function")
    pngData.free();
  if (typeof resvg.free === "function")
    resvg.free();
  return png;
}
async function createJpeg(event) {
  const { sharpOptions } = useOgImageRuntimeConfig();
  if (compatibility.sharp === false) {
    throw new Error("Sharp dependency is not accessible. Please check you have it installed and are using a compatible runtime.");
  }
  const { svg } = await createSvg(event);
  if (!svg) {
    throw new Error("Failed to create SVG for JPEG rendering.");
  }
  const svgBuffer = Buffer.from(svg);
  const sharp = await getSharp().catch(() => {
    throw new Error("Sharp dependency could not be loaded. Please check you have it installed and are using a compatible runtime.");
  });
  const options = defu(event.options.sharp, sharpOptions);
  return sharp(svgBuffer, options).jpeg(options).toBuffer();
}
const SatoriRenderer = {
  name: "satori",
  supportedFormats: ["png", "jpeg", "jpg", "json"],
  async createImage(e) {
    switch (e.extension) {
      case "png":
        return createPng(e);
      case "jpeg":
      case "jpg":
        return createJpeg(e);
    }
  },
  async debug(e) {
    const [vnodes, svgResult] = await Promise.all([
      createVNodes(e),
      createSvg(e)
    ]);
    return {
      vnodes,
      svg: svgResult.svg,
      warnings: svgResult.warnings,
      fontDebug: {
        ...loadAllFontsDebug(e.options.component),
        fonts: svgResult.fonts.map(({ data: _, ...f }) => ({
          ...f,
          size: _.byteLength
        }))
      }
    };
  }
};
export default SatoriRenderer;
