/**
 * Hook useWebSocket – connessione WebSocket al backend PecFlow.
 *
 * Il backend usa FastAPI WebSocket nativo (non Socket.io).
 * Endpoint: /api/v1/ws/{tenant_id}?token=<access_token>
 *
 * Gestisce:
 * - Connessione automatica all'autenticazione
 * - Riconnessione con backoff esponenziale
 * - Dispatch degli eventi all'inbox/mailbox store
 */

import { useEffect, useRef, useCallback } from 'react'
import { useAuthStore } from '@/store/auth.store'
import { useInboxStore } from '@/store/inbox.store'
import { useMailboxStore } from '@/store/mailbox.store'
import type { MessageResponse, WsEvent } from '@/types/api.types'
import toast from 'react-hot-toast'

const MAX_RECONNECT_DELAY = 30000
const BASE_RECONNECT_DELAY = 1000

export function useWebSocket() {
  const wsRef = useRef<WebSocket | null>(null)
  const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const reconnectAttemptsRef = useRef(0)
  const isUnmountedRef = useRef(false)

  const { user, isAuthenticated } = useAuthStore()
  const prependMessage = useInboxStore((s) => s.prependMessage)
  const updateMailboxStatus = useMailboxStore((s) => s.updateMailboxStatus)

  const handleEvent = useCallback(
    (event: WsEvent) => {
      switch (event.type) {
        case 'mailbox:new_message': {
          const message = event.payload as unknown as MessageResponse
          prependMessage(message)
          if (!message.is_read) {
            const from = message.from_address || 'Mittente sconosciuto'
            const subject = message.subject || '(nessun oggetto)'
            toast.success(`📨 Nuova PEC da ${from}: ${subject}`, {
              duration: 5000,
              id: `new-msg-${message.id}`,
            })
          }
          break
        }

        case 'mailbox:status_changed': {
          const { mailbox_id, status, error_msg } = event.payload as {
            mailbox_id: string
            status: string
            error_msg?: string
          }
          updateMailboxStatus(mailbox_id, status, error_msg)
          if (status === 'error') {
            toast.error(`⚠️ Errore sincronizzazione casella`, { duration: 8000 })
          }
          break
        }

        case 'send_job:status_changed': {
          const { job_id: _jobId, status, mailbox_id: _mid } = event.payload as {
            job_id: string
            status: string
            mailbox_id: string
          }
          if (status === 'sent') {
            toast.success('✅ PEC inviata con successo', { duration: 4000 })
          } else if (status === 'failed') {
            toast.error('❌ Invio PEC fallito definitivamente', { duration: 8000 })
          }
          break
        }

        case 'send_job:anomaly': {
          toast.error(
            '⚠️ Anomalia invio PEC: nessuna ricevuta di accettazione entro 24h',
            { duration: 10000 },
          )
          break
        }
      }
    },
    [prependMessage, updateMailboxStatus],
  )

  const connect = useCallback(() => {
    if (!isAuthenticated || !user) return

    const token = localStorage.getItem('access_token')
    if (!token) return

    // Costruisce l'URL WebSocket
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const host = window.location.host
    const wsUrl = `${protocol}//${host}/api/v1/ws/${user.tenant_id}?token=${token}`

    try {
      const ws = new WebSocket(wsUrl)
      wsRef.current = ws

      ws.onopen = () => {
        console.log('[WS] Connessione stabilita')
        reconnectAttemptsRef.current = 0
      }

      ws.onmessage = (event) => {
        try {
          const data = JSON.parse(event.data) as WsEvent
          handleEvent(data)
        } catch {
          console.warn('[WS] Messaggio non valido:', event.data)
        }
      }

      ws.onerror = (error) => {
        console.error('[WS] Errore:', error)
      }

      ws.onclose = (event) => {
        console.log('[WS] Connessione chiusa', event.code, event.reason)
        wsRef.current = null

        if (isUnmountedRef.current || !isAuthenticated) return

        // Backoff esponenziale per la riconnessione
        const delay = Math.min(
          BASE_RECONNECT_DELAY * Math.pow(2, reconnectAttemptsRef.current),
          MAX_RECONNECT_DELAY,
        )
        reconnectAttemptsRef.current += 1

        console.log(`[WS] Riconnessione in ${delay}ms (tentativo ${reconnectAttemptsRef.current})`)
        reconnectTimeoutRef.current = setTimeout(() => {
          if (!isUnmountedRef.current) connect()
        }, delay)
      }
    } catch (error) {
      console.error('[WS] Errore durante la connessione:', error)
    }
  }, [isAuthenticated, user, handleEvent])

  const disconnect = useCallback(() => {
    if (reconnectTimeoutRef.current) {
      clearTimeout(reconnectTimeoutRef.current)
      reconnectTimeoutRef.current = null
    }
    if (wsRef.current) {
      wsRef.current.close(1000, 'Logout')
      wsRef.current = null
    }
  }, [])

  useEffect(() => {
    isUnmountedRef.current = false

    if (isAuthenticated && user) {
      connect()
    } else {
      disconnect()
    }

    return () => {
      isUnmountedRef.current = true
      disconnect()
    }
  }, [isAuthenticated, user?.id, connect, disconnect])

  return { isConnected: wsRef.current?.readyState === WebSocket.OPEN }
}
