'use client'

// PBI-74 / Story 9 / T-880: Client hook for the sprint workspace SSE stream.
// Mounts in SprintHydrationWrapper so it survives Server Action refreshes.
// Dispatches sprint/story/task change events into useSprintWorkspaceStore.
//
// Mirrors use-backlog-realtime.ts:
// - Stream blijft open op tab hidden — gemiste events worden opgehaald via
//   resyncActiveScopes('visible') uit useSprintWorkspaceResync.
// - Latere 'ready'-events (post-reconnect) triggeren
//   resyncActiveScopes('reconnect') zodat events tijdens disconnect alsnog
//   binnenkomen.

import { useEffect, useRef } from 'react'
import { useSprintWorkspaceStore } from '@/stores/sprint-workspace/store'

const BACKOFF_START_MS = 1_000
const BACKOFF_MAX_MS = 30_000

export function useSprintRealtime(productId: string | null) {
  const sourceRef = useRef<EventSource | null>(null)
  const backoffRef = useRef<number>(BACKOFF_START_MS)
  const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const readyCountRef = useRef<number>(0)

  useEffect(() => {
    if (!productId) return

    const close = () => {
      if (sourceRef.current) {
        sourceRef.current.close()
        sourceRef.current = null
      }
      if (reconnectTimerRef.current) {
        clearTimeout(reconnectTimerRef.current)
        reconnectTimerRef.current = null
      }
    }

    const connect = () => {
      close()
      const source = new EventSource(
        `/api/realtime/sprint?product_id=${encodeURIComponent(productId)}`,
      )
      sourceRef.current = source
      useSprintWorkspaceStore.getState().setRealtimeStatus('connecting')

      source.addEventListener('ready', () => {
        backoffRef.current = BACKOFF_START_MS
        readyCountRef.current += 1
        useSprintWorkspaceStore.getState().setRealtimeStatus('open')
        if (readyCountRef.current > 1) {
          void useSprintWorkspaceStore.getState().resyncActiveScopes('reconnect')
        }
      })

      source.onmessage = (e) => {
        if (!e.data) return
        try {
          const payload = JSON.parse(e.data) as Record<string, unknown>
          useSprintWorkspaceStore.getState().applyRealtimeEvent(payload)
        } catch (err) {
          if (process.env.NODE_ENV !== 'production') {
            console.error('[realtime/sprint] failed to parse event', err, e.data)
          }
        }
      }

      source.onerror = () => {
        if (sourceRef.current !== source) return
        close()
        useSprintWorkspaceStore.getState().setRealtimeStatus('disconnected')
        if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return
        const delay = backoffRef.current
        backoffRef.current = Math.min(backoffRef.current * 2, BACKOFF_MAX_MS)
        reconnectTimerRef.current = setTimeout(connect, delay)
      }
    }

    const onVisibility = () => {
      if (document.visibilityState === 'visible' && sourceRef.current === null) {
        backoffRef.current = BACKOFF_START_MS
        connect()
      }
    }

    connect()
    document.addEventListener('visibilitychange', onVisibility)

    return () => {
      document.removeEventListener('visibilitychange', onVisibility)
      close()
      readyCountRef.current = 0
    }
  }, [productId])
}
