// ST-1105: Client hook die de notificatie-SSE stream beheert (M11).
//
// Mount via <NotificationsBridge /> in (app)/layout zodat hij Server Action-
// refreshes overleeft. Opent EventSource('/api/realtime/notifications'),
// dispatcht state-/message-events naar de notifications-store.
//
// Vereenvoudigde versie van useSoloRealtime — geen view-transitions, geen
// connecting-indicator-debounce. Wel: reconnect met exponential backoff en
// pause bij hidden tab.

'use client'

import { useEffect, useRef } from 'react'
import { useNotificationsStore, type NotificationQuestion } from '@/stores/notifications-store'

const BACKOFF_START_MS = 1_000
const BACKOFF_MAX_MS = 30_000

interface NotifyPayload {
  op: 'I' | 'U'
  entity: 'question'
  id: string
  product_id: string
  story_id: string
  task_id: string | null
  assignee_id: string | null
  status: 'open' | 'answered' | 'cancelled' | 'expired'
}

interface StateEvent {
  questions: NotificationQuestion[]
}

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

  useEffect(() => {
    const init = useNotificationsStore.getState().init
    const remove = useNotificationsStore.getState().remove

    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/notifications', {
        withCredentials: true,
      })
      sourceRef.current = source

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

      source.addEventListener('state', (ev) => {
        try {
          const data = JSON.parse((ev as MessageEvent).data) as StateEvent
          init(data.questions ?? [])
        } catch {
          // ignore malformed
        }
      })

      source.addEventListener('message', (ev) => {
        try {
          const payload = JSON.parse(ev.data) as NotifyPayload
          if (payload.entity !== 'question') return
          // Bij open of nieuwe insert → upsert (server stuurt geen vraag-tekst
          // mee in de payload, dus we doen een mini-fetch via de same SSE's
          // initial-state on reconnect; hier voor MVP alleen status-handling).
          if (payload.status === 'open') {
            // Inkomende open vraag: we hebben de details nog niet — beste optie is
            // herfetchen door opnieuw te verbinden, of via een API. Voor v1
            // forceren we een reconnect zodat het volgende state-event de
            // volledige details meelevert.
            close()
            connect()
            return
          }
          // Niet-open status (answered/cancelled/expired) → verwijderen uit lijst
          remove(payload.id)
        } catch {
          // ignore malformed
        }
      })

      source.addEventListener('error', () => {
        // EventSource herconnect zelf bij netwerkfouten; voor server-close
        // (after 240s) doen we een eigen backoff
        if (sourceRef.current?.readyState === EventSource.CLOSED) {
          const delay = backoffRef.current
          backoffRef.current = Math.min(delay * 2, BACKOFF_MAX_MS)
          reconnectTimerRef.current = setTimeout(connect, delay)
        }
      })
    }

    const onVisibilityChange = () => {
      if (document.visibilityState === 'visible') {
        if (!sourceRef.current || sourceRef.current.readyState === EventSource.CLOSED) {
          connect()
        }
      } else {
        close()
      }
    }

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

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