const storagePrefix = "bitview:learn-section";

/** @param {string} id */
function getStorageKey(id) {
  return `${storagePrefix}:${id}`;
}

/** @param {HTMLElement} section */
function getDetails(section) {
  return /** @type {HTMLDetailsElement} */ (
    section.querySelector(":scope > details")
  );
}

/** @param {HTMLElement} section */
function getHash(section) {
  return `#${section.id}`;
}

/**
 * @param {HTMLElement} main
 * @param {HTMLElement} section
 */
function getNavDetails(main, section) {
  const anchor = main.querySelector(`nav a[href="${getHash(section)}"]`);
  const summary = anchor?.parentElement;

  return summary?.localName === "summary" ? summary.parentElement : null;
}

/**
 * @param {HTMLElement} main
 * @param {HTMLElement} section
 */
function syncNavSection(main, section) {
  const details = getNavDetails(main, section);

  if (details) details.toggleAttribute("open", getDetails(section).open);
}

/**
 * @param {HTMLElement} main
 * @param {HTMLElement} section
 */
function openSection(main, section) {
  let current = section;

  while (main.contains(current)) {
    const details = current.querySelector(":scope > details");
    if (details) {
      /** @type {HTMLDetailsElement} */ (details).open = true;
      syncNavSection(main, current);
    }

    const parent = current.parentElement?.closest("section[id]");
    if (!parent) break;
    current = /** @type {HTMLElement} */ (parent);
  }
}

/** @param {Event} event */
function getSectionDetailsEventTarget(event) {
  if (!(event.target instanceof HTMLDetailsElement)) return null;

  const section = event.target.parentElement;

  return section?.matches("article section[id]") ? event.target : null;
}

/** @param {HTMLElement} main */
export function initSectionDetails(main) {
  const sections = [
    ...main.querySelectorAll("section[id]:not([data-numbered='false'])"),
  ].map((section) => /** @type {HTMLElement} */ (section));

  for (const section of sections) {
    const saved = localStorage.getItem(getStorageKey(section.id));

    getDetails(section).open = saved === "1";
    syncNavSection(main, section);
  }

  main.addEventListener("toggle", (event) => {
    const details = getSectionDetailsEventTarget(event);
    if (!details) return;

    const section = /** @type {HTMLElement} */ (details.parentElement);

    localStorage.setItem(getStorageKey(section.id), details.open ? "1" : "0");
    syncNavSection(main, section);
    main.dispatchEvent(new Event("sectiontoggle"));
  }, { capture: true });

  /** @param {string} hash */
  function openHash(hash) {
    const target = document.getElementById(hash.slice(1));

    if (target && main.contains(target)) openSection(main, target);
  }

  /** @param {string} hash */
  function toggleHash(hash) {
    const target = document.getElementById(hash.slice(1));
    if (!target || !main.contains(target)) return false;

    const section = /** @type {HTMLElement} */ (target);
    const details = getDetails(section);

    if (details.open) {
      details.open = false;
      syncNavSection(main, section);
      return false;
    }

    openSection(main, section);
    return true;
  }

  if (window.location.hash) openHash(window.location.hash);

  return {
    openHash,
    toggleHash,
  };
}
