'use client'

import { useEffect, useMemo, useState } from 'react'
import { cn } from '../../utils/cn'

/** Must match MarkdownRenderer's heading id slugify exactly so anchors line up. */
function slugify(text: string): string {
  return text
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/(^-|-$)/g, '')
}

export interface TocItem {
  id: string
  text: string
  level: number
}

/** Parse markdown headings (#, ##, ###) into a flat outline, skipping fenced code. */
export function extractToc(content: string): TocItem[] {
  const items: TocItem[] = []
  let inCode = false
  for (const raw of content.split('\n')) {
    const line = raw.trimEnd()
    if (/^\s*```/.test(line)) {
      inCode = !inCode
      continue
    }
    if (inCode) continue
    const m = /^(#{1,3})\s+(.+?)\s*#*$/.exec(line)
    if (!m) continue
    const text = m[2].replace(/[*_`]/g, '').trim()
    const id = slugify(text)
    if (!id) continue
    items.push({ id, text, level: m[1].length })
  }
  return items
}

export interface TableOfContentsProps {
  content: string
  title?: string
  className?: string
}

/**
 * Sticky left-rail outline for an article, with scroll-spy highlighting.
 * Renders nothing for content with fewer than 2 headings.
 */
export function TableOfContents({ content, title = 'On this page', className }: TableOfContentsProps) {
  const items = useMemo(() => extractToc(content), [content])
  const [activeId, setActiveId] = useState<string | null>(null)

  useEffect(() => {
    if (items.length < 2) return
    const observer = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting) setActiveId(entry.target.id)
        }
      },
      { rootMargin: '0px 0px -70% 0px', threshold: 0 },
    )
    items.forEach((it) => {
      const el = document.getElementById(it.id)
      if (el) observer.observe(el)
    })
    return () => observer.disconnect()
  }, [items])

  if (items.length < 2) return null

  return (
    <nav className={cn('text-sm', className)} aria-label="Table of contents">
      <p className="font-heading text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-3">{title}</p>
      <ul className="border-l border-border">
        {items.map((it) => (
          <li key={it.id} style={{ paddingLeft: `${(Math.min(it.level, 3) - 1) * 12}px` }}>
            <a
              href={`#${it.id}`}
              className={cn(
                'block -ml-px border-l-2 pl-3 py-1 transition-colors',
                activeId === it.id
                  ? 'border-primary text-primary font-medium'
                  : 'border-transparent text-muted-foreground hover:text-foreground',
              )}
            >
              {it.text}
            </a>
          </li>
        ))}
      </ul>
    </nav>
  )
}
