<template>
  <div v-if="alerts.length" class="outage-alerts-panel">
    <div class="outage-alerts-header" @click="expanded = !expanded">
      <q-icon name="warning_amber" color="warning" size="18px" />
      <span class="text-weight-bold">{{ alerts.length }} alerte{{ alerts.length > 1 ? 's' : '' }} réseau</span>
      <q-icon :name="expanded ? 'expand_less' : 'expand_more'" size="18px" class="q-ml-auto" />
    </div>
    <transition name="slide">
      <div v-show="expanded" class="outage-alerts-list">
        <div v-for="a in alerts" :key="a.id" class="outage-alert-item" :class="'outage-alert--' + a.severity">
          <div class="outage-alert-top">
            <q-icon :name="a.type === 'olt' ? 'cell_tower' : a.severity === 'critical' ? 'error' : 'warning'"
              :color="a.severity === 'critical' ? 'red' : a.severity === 'warning' ? 'orange-8' : 'blue-6'" size="16px" />
            <span class="text-weight-medium">
              {{ a.type === 'olt' ? '🔴 OLT ' : '' }}{{ a.oltName }}
              <span v-if="a.port && a.port !== 'ALL' && a.port !== '—'"> : {{ a.port }}</span>
            </span>
            <q-badge :color="a.type === 'olt' ? 'red-10' : a.severity === 'critical' ? 'red' : 'orange'" class="q-ml-xs">
              <template v-if="a.type === 'olt'">~{{ a.affected_count }} clients</template>
              <template v-else>{{ a.affected_count }} client{{ a.affected_count > 1 ? 's' : '' }}</template>
            </q-badge>
            <q-badge v-if="a.source === 'kuma'" outline color="purple" class="q-ml-xs" style="font-size:0.6rem">Kuma</q-badge>
            <span class="text-caption text-grey-6 q-ml-auto">{{ timeAgo(a.ts) }}</span>
          </div>
          <div v-if="a.type === 'olt'" class="text-caption text-grey-7 q-mt-xs">
            OLT complet hors service — tous les clients de cet OLT sont potentiellement affectés
          </div>
          <div v-if="a.ticketId" class="text-caption q-mt-xs">
            Ticket: <span class="text-primary cursor-pointer" @click="$emit('open-ticket', a.ticketId)">{{ a.ticketId }}</span>
            <q-badge v-if="a.notified" color="green" outline class="q-ml-sm" style="font-size:0.6rem">SMS envoyé</q-badge>
          </div>
          <div v-if="a.analysis" class="text-caption text-grey-7 q-mt-xs">
            {{ a.analysis.outage_type }} — {{ a.analysis.action_required }}
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

defineEmits(['open-ticket'])

const HUB_URL = window.location.hostname === 'localhost' ? 'http://localhost:3300' : (import.meta.env.BASE_URL||'/').replace(/\/$/,'')+'/hub'

const alerts = ref([])
const expanded = ref(true)
let es = null
let pollTimer = null
let opened = false          // 1re connexion vs RE-connexion (→ resync)
let reconnectTimer = null

function timeAgo (ts) {
  if (!ts) return ''
  const mins = Math.floor((Date.now() - new Date(ts).getTime()) / 60000)
  if (mins < 1) return "à l'instant"
  if (mins < 60) return `il y a ${mins}m`
  const hrs = Math.floor(mins / 60)
  return hrs < 24 ? `il y a ${hrs}h` : `il y a ${Math.floor(hrs / 24)}j`
}

function addOrUpdateAlert (data) {
  const id = `${data.oltName}:${data.port}`
  const idx = alerts.value.findIndex(a => a.id === id)
  const alert = { id, ...data, ts: data.ts || new Date().toISOString() }
  if (idx >= 0) {
    alerts.value[idx] = alert
  } else {
    alerts.value.unshift(alert)
  }
}

function removeAlert (data) {
  const id = data.type === 'olt' ? `olt:${data.oltName}` : `${data.oltName}:${data.port}`
  alerts.value = alerts.value.filter(a => a.id !== id)
}

// Fetch existing incidents on mount
async function fetchActive () {
  try {
    const res = await fetch(`${HUB_URL}/ai/active-outages`)
    if (res.ok) {
      const { incidents } = await res.json()
      for (const inc of incidents) {
        const id = inc.type === 'olt' ? `olt:${inc.oltName}` : `${inc.oltName}:${inc.port || 'all'}`
        const severity = inc.type === 'olt' ? 'critical' : (inc.affected_count >= 3 ? 'critical' : 'warning')
        addOrUpdateAlert({ ...inc, id, severity })
      }
    }
  } catch {}
}

function connectSSE () {
  if (es) es.close()
  es = new EventSource(`${HUB_URL}/sse?topics=network`)

  es.onopen = () => {
    // (Re)connecté : on stoppe le repli poll. Sur une RE-connexion (ex. après un redéploiement du hub), on
    // resynchronise l'état courant — le hub ne rejoue pas les incidents survenus pendant la coupure.
    if (pollTimer) { clearInterval(pollTimer); pollTimer = null }
    if (opened) fetchActive()
    opened = true
  }

  es.addEventListener('outage-alert', e => {
    try { addOrUpdateAlert({ ...JSON.parse(e.data), severity: 'critical' }) } catch {}
  })
  es.addEventListener('port-alert', e => {
    try { addOrUpdateAlert({ ...JSON.parse(e.data), severity: 'warning' }) } catch {}
  })
  es.addEventListener('outage-resolved', e => {
    try { removeAlert(JSON.parse(e.data)) } catch {}
  })
  // OLT-level events (entire OLT down/up — Kuma or SNMP)
  es.addEventListener('olt-down', e => {
    try {
      const d = JSON.parse(e.data)
      addOrUpdateAlert({ ...d, id: `olt:${d.oltName}`, type: 'olt', port: 'ALL', severity: 'critical' })
    } catch {}
  })
  es.addEventListener('olt-up', e => {
    try {
      const d = JSON.parse(e.data)
      removeAlert({ type: 'olt', oltName: d.oltName })
    } catch {}
  })
  es.addEventListener('kuma-alert', e => {
    try {
      const d = JSON.parse(e.data)
      if (d.status === 0) {
        addOrUpdateAlert({ id: `kuma:${d.monitor}`, oltName: d.monitor, port: '—', affected_count: '?', severity: 'warning', ts: new Date().toISOString(), source: 'kuma' })
      } else {
        alerts.value = alerts.value.filter(a => a.id !== `kuma:${d.monitor}`)
      }
    } catch {}
  })

  es.onerror = () => {
    // Repli immédiat : tant que le flux est coupé, on interroge toutes les 30 s.
    if (!pollTimer) {
      pollTimer = setInterval(fetchActive, 30000)
    }
    // Si le flux est mort DÉFINITIVEMENT (502 pendant un redéploiement du hub → CLOSED, plus de reconnexion
    // native), on relance après 3 s. onopen nettoiera le poll et resynchronisera. Sinon le panneau resterait
    // en mode poll 30 s au lieu du temps réel jusqu'au prochain rechargement.
    if (es && es.readyState === EventSource.CLOSED) {
      es = null
      if (reconnectTimer) clearTimeout(reconnectTimer)
      reconnectTimer = setTimeout(connectSSE, 3000)
    }
  }
}

onMounted(() => {
  fetchActive()
  connectSSE()
})

onUnmounted(() => {
  if (reconnectTimer) clearTimeout(reconnectTimer)
  if (es) es.close()
  if (pollTimer) clearInterval(pollTimer)
})
</script>

<style scoped>
.outage-alerts-panel { border: 1px solid #fed7aa; background: #fffbeb; border-radius: 8px; overflow: hidden; }
.outage-alerts-header { display: flex; align-items: center; gap: 8px; padding: 8px 12px; cursor: pointer; user-select: none; }
.outage-alerts-header:hover { background: #fef3c7; }
.outage-alerts-list { border-top: 1px solid #fed7aa; }
.outage-alert-item { padding: 8px 12px; border-bottom: 1px solid #fef3c7; }
.outage-alert-item:last-child { border-bottom: none; }
.outage-alert-top { display: flex; align-items: center; gap: 6px; }
.outage-alert--critical { background: #fef2f2; }
.outage-alert--warning { background: #fffbeb; }
.slide-enter-active, .slide-leave-active { transition: max-height 0.2s ease, opacity 0.2s ease; overflow: hidden; }
.slide-enter-from, .slide-leave-to { max-height: 0; opacity: 0; }
.slide-enter-to, .slide-leave-from { max-height: 500px; opacity: 1; }
</style>
