import { onBeforeUnmount, ref, type Ref } from 'vue'
import { refreshAccessToken } from '@/shared/api/client'
import { getAccessToken, type AuthScope } from '@/utils/authStorage'

export interface SSEMessage {
  id: number
  conversation_id: number
  sender_type: string
  sender_id: number
  sender_role: string
  sender_name: string
  content_type: string
  content: string
  attachment_urls: string[]
  created_at: string
}

export interface ChatEvent {
  type: 'new_message' | 'conversation_updated'
  conversation_id: number
  message?: SSEMessage
}

type EventHandler = (event: ChatEvent) => void

const reconnectDelay = 3000

export function useChatSSE(scope: AuthScope, endpoint: string) {
  const connected: Ref<boolean> = ref(false)
  let source: EventSource | null = null
  let reconnectTimer: ReturnType<typeof setTimeout> | null = null
  let stopped = false
  let refreshing = false
  const handlers: EventHandler[] = []

  function onEvent(handler: EventHandler) {
    handlers.push(handler)
  }

  function connect() {
    if (stopped || source) return
    const token = getAccessToken(scope)
    if (!token) return

    const url = `${endpoint}?token=${encodeURIComponent(token)}`
    source = new EventSource(url)

    source.addEventListener('connected', () => {
      connected.value = true
    })

    source.addEventListener('new_message', (e) => {
      try {
        const data = JSON.parse((e as MessageEvent).data) as ChatEvent
        handlers.forEach(h => h(data))
      } catch { /* ignore */ }
    })

    source.addEventListener('conversation_updated', (e) => {
      try {
        const data = JSON.parse((e as MessageEvent).data) as ChatEvent
        handlers.forEach(h => h(data))
      } catch { /* ignore */ }
    })

    source.onerror = async () => {
      connected.value = false
      source?.close()
      source = null
      if (stopped || refreshing) return

      refreshing = true
      try {
        await refreshAccessToken(scope)
        if (!stopped) {
          reconnectTimer = setTimeout(connect, reconnectDelay)
        }
      } catch {
        closeSource()
      } finally {
        refreshing = false
      }
    }
  }

  function closeSource() {
    if (reconnectTimer) {
      clearTimeout(reconnectTimer)
      reconnectTimer = null
    }
    source?.close()
    source = null
    connected.value = false
  }

  function handleAuthStorageChanged(event: Event) {
    const detail = (event as CustomEvent<{ scope?: AuthScope }>).detail
    if (detail?.scope !== scope || stopped) return
    closeSource()
    connect()
  }

  function disconnect() {
    stopped = true
    closeSource()
    window.removeEventListener('auth-storage-changed', handleAuthStorageChanged)
  }

  window.addEventListener('auth-storage-changed', handleAuthStorageChanged)

  onBeforeUnmount(() => {
    disconnect()
  })

  connect()

  return { connected, onEvent, disconnect }
}
