/**
 * DOM ready and mutation observer utilities
 */

export type InitCallback = () => void;

let initScheduled = false;
const scheduledCallbacks: Set<InitCallback> = new Set();

/**
 * Schedule initialization callbacks to run on next animation frame
 * Prevents redundant DOM scans during rapid updates
 */
export const scheduleInit = (callback: InitCallback) => {
  scheduledCallbacks.add(callback);

  if (initScheduled) return;
  initScheduled = true;

  // rAF keeps this cheap during rapid DOM updates (page builders).
  requestAnimationFrame(() => {
    initScheduled = false;
    scheduledCallbacks.forEach((cb) => cb());
    // Don't clear callbacks - they should be reusable
  });
};

/**
 * Run callback when DOM is ready, or immediately if already loaded
 */
export const onDomReady = (callback: InitCallback) => {
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", callback);
  } else {
    callback();
  }
};

/**
 * Set up mutation observer to detect new swatch mount points and variation forms
 */
export const observeDomChanges = (callbacks: {
  onSwatchMountAdded?: InitCallback;
  onVariationFormAdded?: InitCallback;
}) => {
  if (typeof MutationObserver === "undefined") return;

  const root = document.body || document.documentElement;
  if (!root) return;

  const observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
      for (const node of Array.from(mutation.addedNodes)) {
        if (!(node instanceof HTMLElement)) continue;

        if (
          node.matches(".b3-wvs-swatches-mount") ||
          node.querySelector(".b3-wvs-swatches-mount")
        ) {
          callbacks.onSwatchMountAdded?.();
          // Builders may also replace the add-to-cart form.
          callbacks.onVariationFormAdded?.();
          return;
        }

        if (
          node.matches("form.variations_form") ||
          node.querySelector("form.variations_form")
        ) {
          callbacks.onVariationFormAdded?.();
          return;
        }
      }
    }
  });

  observer.observe(root, { childList: true, subtree: true });
};
