"use client";

import { useEffect, useRef, useState } from "react";

export type TOCSection = { id: string; title: string };

// How long a click "wins" over the scroll-spy observer — long enough to
// cover the native smooth-scroll animation triggered by the anchor href,
// so sections passing through the viewport mid-scroll can't flicker the
// active state away from what was actually clicked.
const CLICK_OVERRIDE_MS = 1000;

// lg:-only sidebar — same "wide fixed-width block next to content" shape
// as the cart's order-summary sidebar (see figma-to-nextjs skill Gotcha
// #5): a 360px TOC card plus a readable content column already exceeds
// the 768px Tablet floor, so md: wouldn't leave room for a real 2-column
// split at Tablet widths.
//
// Generic over `sections` — originally written just for /versand
// (VersandTOC), generalized once /datenschutz needed the identical
// scroll-spy sidebar but driven by CMS-authored headings instead of a
// hardcoded array. Any future long legal/content page reuses this too.
//
// Not sticky itself — Impressum/Datenschutz put an extra card below this
// in the same sidebar column, and if only this <nav> were sticky, the
// card (a plain-flow sibling) would scroll away independently instead of
// travelling with it. The caller wraps whatever the sidebar column
// contains (this alone, or this + more) in `lg:sticky lg:top-32
// lg:self-start` so the whole column moves as one unit.
export function SectionTOC({ sections }: { sections: TOCSection[] }) {
  const [active, setActive] = useState<string>(sections[0]?.id ?? "");
  // Not state — read inside the IntersectionObserver callback without
  // needing to re-subscribe it on every click, and cleared by its own
  // timeout rather than a render.
  const overrideRef = useRef<string | null>(null);
  const overrideTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);

  useEffect(() => () => clearTimeout(overrideTimeoutRef.current), []);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        // A click just fired — trust it over whatever the scroll-spy sees
        // mid-animation (sections flying past the intersection band while
        // the browser's native smooth-scroll is still catching up to the
        // clicked target), including the case where the target was
        // already fully visible and no scroll happens at all.
        if (overrideRef.current) return;
        const visible = entries.filter((entry) => entry.isIntersecting);
        if (visible.length > 0) setActive(visible[0].target.id);
      },
      { rootMargin: "-120px 0px -65% 0px", threshold: 0 }
    );
    sections.forEach(({ id }) => {
      const el = document.getElementById(id);
      if (el) observer.observe(el);
    });
    return () => observer.disconnect();
  }, [sections]);

  function handleClick(id: string) {
    setActive(id);
    overrideRef.current = id;
    clearTimeout(overrideTimeoutRef.current);
    overrideTimeoutRef.current = setTimeout(() => {
      overrideRef.current = null;
    }, CLICK_OVERRIDE_MS);
  }

  if (sections.length === 0) return null;

  return (
    <nav className="hidden lg:flex flex-col gap-1 w-[22.5rem] shrink-0 bg-bg-base border border-border rounded-md p-6">
      <p className="text-label font-semibold text-text-muted uppercase tracking-wide mb-2">
        Inhaltsübersicht
      </p>
      {sections.map(({ id, title }) => (
        <a
          key={id}
          href={`#${id}`}
          onClick={() => handleClick(id)}
          className={
            "px-3 py-2 rounded-sm text-body-sm transition-colors border-l-2 " +
            (active === id
              ? "border-toc-active-border bg-bg-muted text-text-primary font-semibold"
              : "border-transparent text-text-muted hover:text-text-primary")
          }
        >
          {title}
        </a>
      ))}
    </nav>
  );
}
