import { ref, onUnmounted } from 'vue'

import { HUB_URL } from 'src/config/hub'

/**
 * SSE composable for real-time Communication events from targo-hub.
 *
 * @param {Object} opts
 * @param {Function} opts.onMessage - callback(data) for 'message' events
 * @param {Function} opts.onSmsIncoming - callback(data) for 'sms-incoming' events
 * @param {Function} opts.onSmsStatus - callback(data) for 'sms-status' events
 * @param {Function} opts.onError - callback(event) on connection error
 */
export function useSSE (opts = {}) {
  const connected = ref(false)
  const clientCount = ref(0)
  let es = null
  let reconnectTimer = null
  let reconnectDelay = 1000 // start at 1s, exponential backoff
  let opened = false // pour distinguer 1re connexion vs RECONNEXION (→ resync)

  function connect (topics) {
    disconnect()
    if (!topics || !topics.length) return

    const topicsStr = topics.join(',')
    const url = `${HUB_URL}/sse?topics=${encodeURIComponent(topicsStr)}`

    es = new EventSource(url)

    es.onopen = () => {
      connected.value = true
      reconnectDelay = 1000 // reset backoff on successful connect
      // RESYNC : à toute RE-connexion (après une coupure — ex. redéploiement du hub), on rattrape ce qui a changé pendant
      // l'absence en refetchant l'état (le hub ne rejoue pas les deltas manqués). Pas au tout 1er open (le consommateur charge au mount).
      if (opened && opts.onReconnect) { try { opts.onReconnect() } catch {} }
      opened = true
    }

    es.addEventListener('message', (e) => {
      try {
        const data = JSON.parse(e.data)
        if (opts.onMessage) opts.onMessage(data)
      } catch {}
    })

    es.addEventListener('sms-incoming', (e) => {
      try {
        const data = JSON.parse(e.data)
        if (opts.onSmsIncoming) opts.onSmsIncoming(data)
      } catch {}
    })

    es.addEventListener('sms-status', (e) => {
      try {
        const data = JSON.parse(e.data)
        if (opts.onSmsStatus) opts.onSmsStatus(data)
      } catch {}
    })

    // Événements nommés génériques : opts.listeners = { 'legacy-update': fn, ... }
    if (opts.listeners) {
      for (const [name, cb] of Object.entries(opts.listeners)) {
        es.addEventListener(name, (e) => { try { cb(JSON.parse(e.data)) } catch {} })
      }
    }

    es.onerror = (e) => {
      connected.value = false
      if (opts.onError) opts.onError(e)
      // EventSource auto-reconnects, but if it closes permanently, do manual reconnect
      if (es.readyState === EventSource.CLOSED) {
        scheduleReconnect(topics)
      }
    }
  }

  function scheduleReconnect (topics) {
    if (reconnectTimer) clearTimeout(reconnectTimer)
    reconnectTimer = setTimeout(() => {
      reconnectDelay = Math.min(reconnectDelay * 2, 30000) // max 30s
      connect(topics)
    }, reconnectDelay)
  }

  function disconnect () {
    if (reconnectTimer) {
      clearTimeout(reconnectTimer)
      reconnectTimer = null
    }
    if (es) {
      es.close()
      es = null
    }
    connected.value = false
  }

  onUnmounted(disconnect)

  return { connect, disconnect, connected }
}

/**
 * Send SMS via the hub instead of n8n.
 */
export async function sendSmsViaHub (phone, message, customer) {
  const res = await fetch(`${HUB_URL}/send/sms`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ phone, message, customer }),
  })
  if (!res.ok) {
    const err = await res.text().catch(() => 'Unknown error')
    throw new Error('SMS failed (' + res.status + '): ' + err)
  }
  return res.json()
}
