const LOTTIE_SCRIPT = "https://cdn.jsdelivr.net/npm/lottie-web@5.12.2/build/player/lottie.min.js";

/** @type {Promise<typeof lottie>|null} */
let lottieLoadPromise = null;

/** @type {WeakMap<HTMLElement, import('lottie-web').AnimationItem>} */
const instances = new WeakMap();

function prefersReducedMotion() {
  return globalThis.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches === true;
}

function loadLottieLib() {
  if (globalThis.lottie?.loadAnimation) return Promise.resolve(globalThis.lottie);
  if (!lottieLoadPromise) {
    lottieLoadPromise = new Promise((resolve, reject) => {
      const existing = document.querySelector('script[data-lottie-web="1"]');
      if (existing) {
        existing.addEventListener("load", () => resolve(globalThis.lottie), { once: true });
        existing.addEventListener("error", reject, { once: true });
        return;
      }
      const script = document.createElement("script");
      script.src = LOTTIE_SCRIPT;
      script.async = true;
      script.dataset.lottieWeb = "1";
      script.onload = () => resolve(globalThis.lottie);
      script.onerror = () => reject(new Error("lottie-web failed to load"));
      document.head.appendChild(script);
    });
  }
  return lottieLoadPromise;
}

function showFallback(host, fallbackSrc) {
  if (!fallbackSrc || host.querySelector("img")) return;
  host.innerHTML = `<img src="${fallbackSrc}" alt="" class="h-full w-full object-contain" width="48" height="48" decoding="async" />`;
}

/**
 * @param {HTMLElement} host
 * @param {{ src: string, fallbackSrc?: string, loop?: boolean }} opts
 */
export async function mountLottieIcon(host, opts) {
  if (!host || !(host instanceof HTMLElement)) return null;

  const prev = instances.get(host);
  if (prev) {
    prev.destroy();
    instances.delete(host);
  }
  host.innerHTML = "";

  const { src, fallbackSrc = "", loop = true } = opts;
  if (!src) {
    showFallback(host, fallbackSrc);
    return null;
  }

  if (prefersReducedMotion()) {
    showFallback(host, fallbackSrc);
    return null;
  }

  try {
    const lottie = await loadLottieLib();
    const res = await fetch(src);
    if (!res.ok) throw new Error(`Lottie fetch ${res.status}`);
    const animationData = await res.json();
    const anim = lottie.loadAnimation({
      container: host,
      renderer: "svg",
      loop,
      autoplay: true,
      animationData,
      rendererSettings: { preserveAspectRatio: "xMidYMid meet" },
    });
    instances.set(host, anim);
    anim.addEventListener("data_failed", () => {
      anim.destroy();
      instances.delete(host);
      showFallback(host, fallbackSrc);
    });
    return anim;
  } catch {
    showFallback(host, fallbackSrc);
    return null;
  }
}

/** @param {ParentNode|null|undefined} root */
export function destroyLottieIcons(root) {
  if (!root || !("querySelectorAll" in root)) return;
  root.querySelectorAll(".lottie-icon-host").forEach((host) => {
    if (!(host instanceof HTMLElement)) return;
    const anim = instances.get(host);
    if (anim) {
      anim.destroy();
      instances.delete(host);
    }
    host.innerHTML = "";
  });
}

/** @param {ParentNode|null|undefined} root */
export function mountLottieIcons(root) {
  if (!root || !("querySelectorAll" in root)) return;
  root.querySelectorAll(".lottie-icon-host[data-lottie-src]").forEach((host) => {
    if (!(host instanceof HTMLElement)) return;
    const src = host.dataset.lottieSrc || "";
    const fallbackSrc = host.dataset.lottieFallback || "";
    void mountLottieIcon(host, { src, fallbackSrc });
  });
}
