// a prose page's list follows the section you're reading. clicking one (or following a #link)
// picks it and lights it up in the page, and that pick holds even when the page can't scroll
// it to the top, until you scroll yourself.

import { tree } from "./tree";

const list = document.querySelector<HTMLElement>(".pane:not(.cfg-pane) > [data-tree]");
if (list) setup(list);

function setup(list: HTMLElement) {
  const outline = tree(list);
  const keys = [...list.querySelectorAll<HTMLElement>("[data-to]")].map((a) => a.dataset.to!).filter(Boolean);
  const headings = keys.map((k) => document.getElementById(k)).filter((h): h is HTMLElement => !!h);
  let pinned: string | null = null;
  let tick = 0;

  const spy = () => {
    tick = 0;
    if (pinned !== null) return;
    const line = window.innerHeight * 0.3;
    let cur = "";
    for (const h of headings) if (h.getBoundingClientRect().top < line) cur = h.id;
    outline.select(cur);
  };

  const pin = (key: string) => {
    pinned = key;
    outline.select(key);
    const h = key && document.getElementById(key);
    if (!h) return;
    h.classList.remove("flash");
    void h.offsetWidth;
    h.classList.add("flash");
  };
  const unpin = () => {
    if (pinned === null) return;
    pinned = null;
    spy();
  };

  window.addEventListener("scroll", () => (tick ||= requestAnimationFrame(spy)), { passive: true });
  // only the reader's own scrolling lets the page take the list back
  window.addEventListener("wheel", unpin, { passive: true });
  window.addEventListener("touchmove", unpin, { passive: true });
  window.addEventListener("keydown", (e) => {
    if (["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "].includes(e.key) && !list.contains(e.target as Node)) unpin();
  });
  // a press on the page's scrollbar lands on <html>
  window.addEventListener("mousedown", (e) => e.target === document.documentElement && unpin());
  window.addEventListener("hashchange", () => pin(decodeURIComponent(location.hash.slice(1))));
  list.addEventListener("click", (e) => {
    const a = (e.target as HTMLElement).closest<HTMLAnchorElement>("a[data-to]");
    if (!a) return;
    if (a.dataset.to === "") {
      e.preventDefault();
      history.pushState(null, "", location.pathname);
      window.scrollTo({ top: 0 });
    }
    // the hash may not change (clicking the same entry twice), so pin here too
    pin(a.dataset.to!);
  });

  if (location.hash) pin(decodeURIComponent(location.hash.slice(1)));
  else spy();
}

export {};
