import { useEffect, useState } from 'react'
import { HubConnection, HubConnectionBuilder, HubConnectionState, LogLevel } from '@microsoft/signalr'
import { getAccessToken } from '@/lib/auth'
import { getOrgOverride } from '@/lib/api'

/**
 * Bridge между фронтом и API SignalR-хабом `/hubs/notifications`.
 * Подписка живёт на всё время монтирования компонента (обычно AppLayout).
 *
 * События:
 *  - SalePosted   → { saleId, number, total, storeId, cashierName, retailPointId, postedAt }
 *  - SupplyPosted → { supplyId, number, total, supplierId, supplierName, postedAt }
 *  - LowStock     → { productId, productName, storeId, storeName, quantity, minStock }
 *
 * Поля приходят camelCase (System.Text.Json по умолчанию пишет именно так,
 * хотя record-DTO именованы PascalCase — это нормально).
 *
 * Auto-reconnect через built-in withAutomaticReconnect — после отключения
 * (например задержка сети) клиент сам пересоединится. Только в случае
 * сменa access_token нужно ручное reconnect (мы делаем это через ключ
 * tokenChanged — в App.tsx, если будет нужно).
 *
 * Если SignalR не доступен (например на стейдже не задеплоен) — компонент
 * не падает, просто isConnected=false.
 */
export interface SalePostedPayload {
  saleId: string
  number: string
  total: number
  storeId: string
  cashierName: string | null
  retailPointId: string | null
  postedAt: string
}
export interface SupplyPostedPayload {
  supplyId: string
  number: string
  total: number
  supplierId: string
  supplierName: string | null
  postedAt: string
}
export interface LowStockPayload {
  productId: string
  productName: string
  storeId: string
  storeName: string | null
  quantity: number
  minStock: number
}

export interface NotificationsHandlers {
  onSalePosted?: (p: SalePostedPayload) => void
  onSupplyPosted?: (p: SupplyPostedPayload) => void
  onLowStock?: (p: LowStockPayload) => void
}

export function useNotificationsHub(handlers: NotificationsHandlers) {
  const [isConnected, setIsConnected] = useState(false)
  useEffect(() => {
    const token = getAccessToken()
    if (!token) return
    const override = getOrgOverride()
    const url = new URL('/hubs/notifications', window.location.origin)
    if (override?.id) url.searchParams.set('orgOverride', override.id)
    // access_token передаём через accessTokenFactory (билдер сам подставит
    // его в query при WebSocket-handshake'е).
    let cancelled = false
    const conn: HubConnection = new HubConnectionBuilder()
      .withUrl(url.toString(), { accessTokenFactory: () => getAccessToken() ?? '' })
      .withAutomaticReconnect()
      .configureLogging(LogLevel.Warning)
      .build()

    if (handlers.onSalePosted) conn.on('SalePosted', handlers.onSalePosted)
    if (handlers.onSupplyPosted) conn.on('SupplyPosted', handlers.onSupplyPosted)
    if (handlers.onLowStock) conn.on('LowStock', handlers.onLowStock)
    conn.onreconnected(() => setIsConnected(true))
    conn.onreconnecting(() => setIsConnected(false))
    conn.onclose(() => setIsConnected(false))

    conn.start()
      .then(() => { if (!cancelled) setIsConnected(conn.state === HubConnectionState.Connected) })
      .catch((e) => {
        // Не падаем. На фронте отсутствие live-обновлений = деградация, не баг.
        console.warn('[SignalR] connect failed:', e instanceof Error ? e.message : e)
      })

    return () => {
      cancelled = true
      conn.stop().catch(() => {})
    }
    // handlers стабильны — React.memo / useCallback на стороне caller'а,
    // не пересоздаём connection на каждый рендер
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  return { isConnected }
}
