function debounce(func, wait = 100, immediate = false) {
  let timeout;
  return function () {
    const context = this,
      args = arguments;
    const later = function () {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

let loadingPromise = undefined;
let echartsIsInitialized = false;

async function loadEChartsScript() {
  if (loadingPromise) {
    return loadingPromise;
  }

  const script = document.createElement("script");
  script.src = "/js/echarts.min.js";
  script.async = true;

  loadingPromise = new Promise((resolve, reject) => {
    script.onload = () => {
      resolve(window.echarts);
    };
    script.onerror = reject;
  });

  document.head.appendChild(script);

  return loadingPromise;
}

if (!echartsIsInitialized) {
  echartsIsInitialized = true;

  const chartInstances = new Map();
  const observer = new IntersectionObserver(
    (entries, observer) => {
      for (const entry of entries) {
        const { target: chartElement, isIntersecting, isVisible } = entry;
        const echartsOptionsPath = chartElement.getAttribute("data-chart-data");
        const there = isIntersecting || isVisible;

        if (
          !echartsOptionsPath ||
          !there ||
          chartInstances.has(echartsOptionsPath)
        ) {
          return;
        }

        (async () => {
          try {
            const echarts = await loadEChartsScript();
            const response = await fetch(echartsOptionsPath);
            const echartsOptions = await response.json();
            const chart = echarts.init(chartElement);

            chart.setOption({
              ...echartsOptions,
              animation: true,
            });
            chartInstances.set(echartsOptionsPath, chart);
          } catch (e) {
            console.error(e);
          }
        })();
      }
    },
    {
      rootMargin: "33%",
      threshold: 0,
    },
  );

  document.addEventListener("DOMContentLoaded", () => {
    const charts = document.querySelectorAll("[data-chart-data]");

    for (const chart of charts) {
      observer.observe(chart);
    }
  });

  window.addEventListener(
    "resize",
    debounce(() => {
      for (const chart of chartInstances.values()) {
        chart.resize();
      }
    }),
  );
}
