'use client'

import { useEffect, useRef, useState } from 'react'

type TocItem = { text: string; id: string; level: number }

const indentByLevel: Record<number, string> = {
  2: 'pl-0',
  3: 'pl-4',
}

export function TableOfContents({ items }: { items: TocItem[] }) {
  const [activeId, setActiveId] = useState<string | null>(null)
  const observer = useRef<IntersectionObserver | null>(null)

  useEffect(() => {
    if (items.length === 0) return

    const headingElements = items
      .map((item) => document.getElementById(item.id))
      .filter((el): el is HTMLElement => el !== null)

    observer.current = new IntersectionObserver(
      (entries) => {
        const visible = entries.filter((entry) => entry.isIntersecting)
        if (visible.length > 0) {
          setActiveId(visible[0].target.id)
        }
      },
      { rootMargin: '0px 0px -70% 0px', threshold: 1.0 },
    )

    headingElements.forEach((el) => observer.current?.observe(el))

    return () => observer.current?.disconnect()
  }, [items])

  if (items.length === 0) return null

  return (
    <aside className="hidden lg:block w-80 2xl:w-100">
      <nav
        aria-label="Table of contents"
        className="sticky top-12 border-l border-border h-fit pl-4 py-4"
      >
        <h2 className="text-xl font-bold mb-4">Table of Contents</h2>
        <ul className="space-y-1 text-sm">
          {items.map((item) => (
            <li key={item.id} className={indentByLevel[item.level] ?? 'pl-0'}>
              <a
                href={`#${item.id}`}
                className={`block truncate transition-colors ${
                  activeId === item.id ? 'text-accent font-medium' : 'text-fg-dim hover:text-fg'
                }`}
                aria-current={activeId === item.id ? 'location' : undefined}
              >
                {item.text}
              </a>
            </li>
          ))}
        </ul>
      </nav>
    </aside>
  )
}
