declare global {
  interface Window {
    MathJax?: {
      startup?: {
        promise?: Promise<unknown>;
      };
      typesetPromise?: (elements?: HTMLElement[]) => Promise<unknown>;
      typesetClear?: (elements?: HTMLElement[]) => void;
    };
  }
}

const MATHJAX_SCRIPT_ID = "glitch-player-mathjax";
const MATHJAX_SRC = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js";

let mathJaxPromise: Promise<void> | null = null;

export function ensureMathJax(): Promise<void> {
  if (typeof window === "undefined" || typeof document === "undefined") {
    return Promise.resolve();
  }

  if (window.MathJax?.typesetPromise) {
    return Promise.resolve();
  }

  if (mathJaxPromise) {
    return mathJaxPromise;
  }

  mathJaxPromise = new Promise<void>((resolve, reject) => {
    window.MathJax = window.MathJax ?? {};

    const existingScript = document.getElementById(
      MATHJAX_SCRIPT_ID
    ) as HTMLScriptElement | null;

    const onLoad = () => {
      if (existingScript) {
        existingScript.dataset.loaded = "true";
      }

      const startupPromise = window.MathJax?.startup?.promise;
      if (startupPromise) {
        void startupPromise.then(() => resolve()).catch(reject);
        return;
      }

      resolve();
    };

    if (existingScript) {
      if (
        existingScript.dataset.loaded === "true" ||
        window.MathJax?.typesetPromise
      ) {
        onLoad();
        return;
      }

      existingScript.addEventListener("load", onLoad, { once: true });
      existingScript.addEventListener(
        "error",
        () => reject(new Error("Failed to load MathJax.")),
        { once: true }
      );
      return;
    }

    const script = document.createElement("script");
    script.id = MATHJAX_SCRIPT_ID;
    script.async = true;
    script.src = MATHJAX_SRC;
    script.addEventListener(
      "load",
      () => {
        script.dataset.loaded = "true";
        onLoad();
      },
      { once: true }
    );
    script.addEventListener(
      "error",
      () => reject(new Error("Failed to load MathJax.")),
      { once: true }
    );
    document.head.appendChild(script);
  });

  return mathJaxPromise;
}
