/**
 * Single subscriber for viewport zoom: one component (ViewportDisplayProvider)
 * subscribes to useViewport() and provides displayMode so contextual nodes
 * don't each subscribe to viewport and re-render on every pan/zoom.
 */

import React, { useLayoutEffect, useRef, useState } from 'react'
import { useViewport } from '@xyflow/react'
import { CONTEXTUAL_ZOOM_THRESHOLD } from '@/app/canvas/ContextualZoomNode'

export type ViewportDisplayMode = 'compact' | 'full'

const HYSTERESIS = 0.02

const ViewportDisplayContext = React.createContext<ViewportDisplayMode>('full')
export { ViewportDisplayContext }

/**
 * Must be rendered inside ReactFlowProvider. Subscribes to viewport once,
 * maps zoom to displayMode with hysteresis. Throttles updates via rAF to avoid
 * re-rendering all contextual nodes on every zoom tick.
 */
export function ViewportDisplayProvider({ children }: { children: React.ReactNode }) {
  const { zoom } = useViewport()
  const [displayMode, setDisplayMode] = useState<ViewportDisplayMode>(() =>
    zoom <= CONTEXTUAL_ZOOM_THRESHOLD ? 'compact' : 'full'
  )
  const lastModeRef = useRef(displayMode)
  const zoomRef = useRef(zoom)
  const rafRef = useRef<number | null>(null)
  zoomRef.current = zoom

  useLayoutEffect(() => {
    if (rafRef.current !== null) return
    rafRef.current = requestAnimationFrame(() => {
      rafRef.current = null
      const z = zoomRef.current
      const low = CONTEXTUAL_ZOOM_THRESHOLD - HYSTERESIS
      const high = CONTEXTUAL_ZOOM_THRESHOLD + HYSTERESIS
      let next: ViewportDisplayMode = lastModeRef.current
      if (z <= low) next = 'compact'
      else if (z >= high) next = 'full'
      if (next !== lastModeRef.current) {
        lastModeRef.current = next
        setDisplayMode(next)
      }
    })
  }, [zoom])

  return (
    <ViewportDisplayContext.Provider value={displayMode}>
      {children}
    </ViewportDisplayContext.Provider>
  )
}
