// src/hooks/useRealtimeUpdates.ts
// React Hook für Real-time Community Updates via SSE

'use client'

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

// =============================================================================
// Types
// =============================================================================

export type UpdateType = 'new_interaction' | 'status_change' | 'new_reply'

export interface CommunityUpdate {
  type: UpdateType
  data: {
    id: number
    platform?: string
    authorName?: string
    content?: string
    sentiment?: string
    sourceTitle?: string
    status?: string
    ourReply?: string
    createdAt?: string
    updatedAt?: string
    repliedAt?: string
  }
  timestamp: string
}

export interface SSEMessage {
  type: 'connected' | 'updates' | 'heartbeat' | 'error' | 'reconnect'
  updates?: CommunityUpdate[]
  message?: string
  timestamp: string
}

export interface UseRealtimeUpdatesOptions {
  /** Channel-IDs für Filterung */
  channelIds?: number[]
  /** Automatisch verbinden beim Mount */
  autoConnect?: boolean
  /** Max. Anzahl Updates im State */
  maxUpdates?: number
  /** Callback für neue Updates */
  onUpdate?: (updates: CommunityUpdate[]) => void
  /** Callback für Verbindungsstatus */
  onConnectionChange?: (connected: boolean) => void
}

export interface UseRealtimeUpdatesReturn {
  /** Verbindungsstatus */
  connected: boolean
  /** Verbindung wird aufgebaut */
  connecting: boolean
  /** Alle empfangenen Updates */
  updates: CommunityUpdate[]
  /** Anzahl neuer Interaktionen seit letztem Clear */
  newCount: number
  /** Letzter Fehler */
  error: string | null
  /** Manuell verbinden */
  connect: () => void
  /** Verbindung trennen */
  disconnect: () => void
  /** Updates zurücksetzen */
  clearUpdates: () => void
  /** NewCount zurücksetzen */
  clearNewCount: () => void
}

// =============================================================================
// Hook Implementation
// =============================================================================

export function useRealtimeUpdates(
  options: UseRealtimeUpdatesOptions = {}
): UseRealtimeUpdatesReturn {
  const {
    channelIds = [],
    autoConnect = true,
    maxUpdates = 100,
    onUpdate,
    onConnectionChange,
  } = options

  const [connected, setConnected] = useState(false)
  const [connecting, setConnecting] = useState(false)
  const [updates, setUpdates] = useState<CommunityUpdate[]>([])
  const [newCount, setNewCount] = useState(0)
  const [error, setError] = useState<string | null>(null)

  const eventSourceRef = useRef<EventSource | null>(null)
  const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null)
  const lastTimestampRef = useRef<string | null>(null)
  const connectRef = useRef<() => void>(() => {})

  // Callbacks als Refs speichern um Dependency-Probleme zu vermeiden
  const onUpdateRef = useRef(onUpdate)
  const onConnectionChangeRef = useRef(onConnectionChange)
  useEffect(() => {
    onUpdateRef.current = onUpdate
    onConnectionChangeRef.current = onConnectionChange
  })

  /**
   * Reconnect nach Verzögerung planen
   */
  const scheduleReconnect = useCallback(() => {
    if (reconnectTimeoutRef.current) {
      return // Bereits geplant
    }

    reconnectTimeoutRef.current = setTimeout(() => {
      reconnectTimeoutRef.current = null
      connectRef.current()
    }, 3000) // 3 Sekunden warten
  }, [])

  /**
   * Verbindung herstellen
   */
  const connect = useCallback(() => {
    // Bereits verbunden oder verbindend
    if (eventSourceRef.current || connecting) {
      return
    }

    setConnecting(true)
    setError(null)

    // URL mit Query-Parametern aufbauen
    const params = new URLSearchParams()
    if (lastTimestampRef.current) {
      params.set('since', lastTimestampRef.current)
    }
    if (channelIds.length > 0) {
      params.set('channels', channelIds.join(','))
    }

    const url = `/api/community/stream${params.toString() ? `?${params.toString()}` : ''}`

    try {
      const eventSource = new EventSource(url)
      eventSourceRef.current = eventSource

      eventSource.onopen = () => {
        setConnecting(false)
        setConnected(true)
        setError(null)
        onConnectionChangeRef.current?.(true)
      }

      eventSource.onmessage = (event) => {
        try {
          const message: SSEMessage = JSON.parse(event.data)

          switch (message.type) {
            case 'connected':
              console.log('[SSE] Connected:', message.message)
              break

            case 'updates':
              if (message.updates && message.updates.length > 0) {
                setUpdates((prev) => {
                  const newUpdates = [...message.updates!, ...prev].slice(0, maxUpdates)
                  return newUpdates
                })

                // Neue Interaktionen zählen
                const newInteractions = message.updates.filter(
                  (u) => u.type === 'new_interaction'
                ).length
                if (newInteractions > 0) {
                  setNewCount((prev) => prev + newInteractions)
                }

                // Callback aufrufen
                onUpdateRef.current?.(message.updates)

                // Timestamp aktualisieren
                lastTimestampRef.current = message.timestamp
              }
              break

            case 'heartbeat':
              // Heartbeat - nichts tun
              break

            case 'error':
              console.error('[SSE] Server error:', message.message)
              setError(message.message || 'Server error')
              break

            case 'reconnect':
              // Server fordert Reconnect an
              console.log('[SSE] Reconnect requested')
              eventSource.close()
              eventSourceRef.current = null
              scheduleReconnect()
              break
          }
        } catch (e) {
          console.error('[SSE] Error parsing message:', e)
        }
      }

      eventSource.onerror = (e) => {
        console.error('[SSE] Connection error:', e)
        setConnected(false)
        setConnecting(false)
        onConnectionChangeRef.current?.(false)

        // EventSource schließen und Reconnect planen
        eventSource.close()
        eventSourceRef.current = null
        scheduleReconnect()
      }
    } catch (e) {
      console.error('[SSE] Failed to create EventSource:', e)
      setConnecting(false)
      setError('Failed to connect')
    }
  }, [channelIds, connecting, maxUpdates, scheduleReconnect])

  // Keep ref in sync so scheduleReconnect can call latest connect
  useEffect(() => {
    connectRef.current = connect
  })

  /**
   * Verbindung trennen
   */
  const disconnect = useCallback(() => {
    if (reconnectTimeoutRef.current) {
      clearTimeout(reconnectTimeoutRef.current)
      reconnectTimeoutRef.current = null
    }

    if (eventSourceRef.current) {
      eventSourceRef.current.close()
      eventSourceRef.current = null
    }

    setConnected(false)
    setConnecting(false)
    onConnectionChangeRef.current?.(false)
  }, [])

  /**
   * Updates zurücksetzen
   */
  const clearUpdates = useCallback(() => {
    setUpdates([])
  }, [])

  /**
   * NewCount zurücksetzen
   */
  const clearNewCount = useCallback(() => {
    setNewCount(0)
  }, [])

  // Auto-Connect beim Mount (SSE external system subscription)
  useEffect(() => {
    if (autoConnect) {
      // eslint-disable-next-line react-hooks/set-state-in-effect -- SSE subscription pattern
      connect()
    }

    return () => {
      disconnect()
    }
  }, [autoConnect, connect, disconnect])

  // Channel-IDs Änderung: Reconnect
  useEffect(() => {
    if (connected || connecting) {
      // eslint-disable-next-line react-hooks/set-state-in-effect -- SSE reconnect pattern
      disconnect()
      // Kurz warten, dann neu verbinden
      const timeout = setTimeout(() => {
        connect()
      }, 100)
      return () => clearTimeout(timeout)
    }
  }, [channelIds.join(',')]) // eslint-disable-line react-hooks/exhaustive-deps

  return {
    connected,
    connecting,
    updates,
    newCount,
    error,
    connect,
    disconnect,
    clearUpdates,
    clearNewCount,
  }
}

export default useRealtimeUpdates
