'use client'

// ST-1115: Client hook for the backlog 3-pane SSE stream.
// Mounts in BacklogHydrationWrapper so it survives Server Action refreshes.
// Dispatches pbi/story/task change events into useBacklogStore.applyChange.

import { useEffect, useRef } from 'react'
import { useBacklogStore } from '@/stores/backlog-store'

const BACKOFF_START_MS = 1_000
const BACKOFF_MAX_MS = 30_000

type EntityPayload = {
  op: 'I' | 'U' | 'D'
  entity: 'pbi' | 'story' | 'task'
  [key: string]: unknown
}

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

  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/backlog?product_id=${encodeURIComponent(productId)}`,
      )
      sourceRef.current = source

      source.addEventListener('ready', () => {
        backoffRef.current = BACKOFF_START_MS
      })

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

      source.onerror = () => {
        if (sourceRef.current !== source) return
        close()
        if (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 === 'hidden') {
        close()
      } else if (sourceRef.current === null) {
        backoffRef.current = BACKOFF_START_MS
        connect()
      }
    }

    if (document.visibilityState === 'visible') {
      connect()
    }
    document.addEventListener('visibilitychange', onVisibility)

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