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

/**
 * Detects whether a sentinel element has scrolled above the top of the
 * nearest scroll container (the AppShell's `main.content-scroll`).
 * Returns `true` when the user has moved past the sentinel, `false`
 * while the sentinel is still in or below the viewport.
 *
 * Uses a ref-callback API rather than a `useRef` so the listener
 * actually attaches when the sentinel mounts. With a plain useRef the
 * setup effect runs once on first commit - which on pages that show a
 * skeleton until data loads is BEFORE the real sentinel div renders,
 * leaving `ref.current` null and the listener never wired up.
 *
 * Usage:
 *   const { sentinelRef, past } = usePastSentinel()
 *   return <div ref={sentinelRef} />
 */
export function usePastSentinel(): {
  sentinelRef: (el: HTMLElement | null) => void
  past: boolean
} {
  const [el, setEl] = useState<HTMLElement | null>(null)
  const [past, setPast] = useState(false)

  // Wrap the state setter so React doesn't change the callback identity
  // every render - the `ref` prop sees a stable function.
  const sentinelRef = useCallback((next: HTMLElement | null) => {
    setEl(next)
  }, [])

  useEffect(() => {
    if (!el) return
    const root = (document.querySelector('main.content-scroll') as HTMLElement | null) || null
    let raf = 0
    const update = () => {
      raf = 0
      const rect = el.getBoundingClientRect()
      const rootTop = root ? root.getBoundingClientRect().top : 0
      setPast(rect.top <= rootTop + 1)
    }
    const schedule = () => {
      if (raf) return
      raf = requestAnimationFrame(update)
    }
    schedule()
    const target: EventTarget = root || window
    target.addEventListener('scroll', schedule, { passive: true })
    const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(schedule) : null
    ro?.observe(el)
    return () => {
      if (raf) cancelAnimationFrame(raf)
      target.removeEventListener('scroll', schedule)
      ro?.disconnect()
    }
  }, [el])

  return { sentinelRef, past }
}
