<!--
  OnuActionsPanel — actions cycle-de-vie ONU (fibre TP-Link tech-3) depuis la fiche appareil.
  Modèle plan → confirm → run : chaque action AFFICHE d'abord l'aperçu (hub /olt/onu/plan, LECTURE SEULE :
  OLT/slot/port résolus, payload n8n exact, effets, avertissements), et n'EXÉCUTE (/olt/onu/run) qu'à la
  confirmation, avec une clé d'idempotence (re-clic = pas de 2e tir). Réservé tech-3 (n8n) ; tech-2 (Raisecom)
  → le plan indique « SNMP direct côté F » et bloque l'exécution. Autonome : n'appelle que le hub.
-->
<template>
  <div v-if="serial" class="q-mt-md">
    <div class="info-block-title"><q-icon name="settings_input_antenna" size="16px" class="q-mr-xs" />Actions ONU (fibre)</div>
    <div class="text-caption text-grey-6 q-mb-xs">Chaque action montre un aperçu avant d’exécuter. Modifie le réseau du client.</div>
    <div class="row q-gutter-xs">
      <q-btn v-for="a in menu" :key="a.action" outline dense no-caps size="sm" :color="a.color || 'grey-8'"
        :icon="a.icon" :label="a.label" @click="openAction(a.action)" />
    </div>

    <q-dialog v-model="dlg">
      <q-card style="min-width:340px;max-width:94vw">
        <q-card-section class="row items-center q-pb-xs">
          <div class="text-subtitle1 text-weight-bold">{{ planData ? planData.label : 'Action ONU' }}</div>
          <q-space />
          <q-badge v-if="planData && planData.tech" :color="planData.tech === 3 ? 'teal-6' : 'orange-7'">tech-{{ planData.tech }}</q-badge>
        </q-card-section>
        <q-separator />
        <q-card-section class="q-gutter-sm">
          <!-- Entrées propres à certaines actions -->
          <q-input v-if="curAction === 'replace'" v-model="newSn" dense outlined label="Nouvelle série (new_sn)" @update:model-value="loadPlan" />
          <q-input v-if="curAction === 'speed' || curAction === 'activate'" v-model="profileId" dense outlined label="Profil de ligne (profileid)" @update:model-value="loadPlan" />

          <div v-if="planLoading" class="text-center q-pa-md"><q-spinner size="26px" color="primary" /></div>
          <template v-else-if="planData">
            <!-- Cible -->
            <div class="oa-target">
              <div><span class="oa-k">Série</span>{{ planData.target.serial || '—' }}</div>
              <div><span class="oa-k">OLT</span>{{ planData.target.olt || '—' }}<span v-if="planData.target.slot != null"> · {{ planData.target.slot }}/{{ planData.target.port }}/{{ planData.target.ontid }}</span></div>
              <div v-if="planData.customer"><span class="oa-k">Client</span>{{ planData.customer }}</div>
              <div><span class="oa-k">Appel</span><code>{{ planData.verb }} dostuff</code></div>
            </div>
            <!-- Effets -->
            <ul v-if="planData.effects && planData.effects.length" class="oa-effects">
              <li v-for="(e, i) in planData.effects" :key="i">{{ e }}</li>
            </ul>
            <!-- Avertissements -->
            <q-banner v-if="planData.warnings && planData.warnings.length" dense class="bg-orange-1 text-orange-9 oa-warn">
              <template #avatar><q-icon name="warning" color="orange-8" /></template>
              <div v-for="(w, i) in planData.warnings" :key="i" class="oa-warn-line">{{ w }}</div>
            </q-banner>
          </template>
          <div v-else class="text-negative text-caption">{{ planError || 'Aperçu indisponible.' }}</div>
        </q-card-section>
        <q-separator />
        <q-card-actions align="right">
          <q-btn flat no-caps label="Annuler" color="grey-8" v-close-popup :disable="running" />
          <q-btn unelevated no-caps :label="'Exécuter — ' + (planData ? planData.label : '')" color="negative"
            :loading="running" :disable="!planData || !planData.can_run" @click="doRun" />
        </q-card-actions>
      </q-card>
    </q-dialog>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { Notify } from 'quasar'
import { HUB_URL } from 'src/config/hub'

const props = defineProps({
  serial: { type: String, default: '' },
  olt: { type: String, default: '' },
  status: { type: String, default: '' }, // statut courant (Actif/Suspendu…) pour proposer suspend vs unsuspend
})
const emit = defineEmits(['changed'])

const menu = [
  { action: 'suspend', label: 'Suspendre', icon: 'pause_circle', color: 'orange-8' },
  { action: 'unsuspend', label: 'Rétablir', icon: 'play_circle', color: 'green-7' },
  { action: 'reboot', label: 'Redémarrer', icon: 'restart_alt', color: 'blue-grey-7' },
  { action: 'speed', label: 'Forfait / vitesse', icon: 'speed', color: 'blue-7' },
  { action: 'replace', label: 'Remplacer', icon: 'swap_horiz', color: 'deep-purple-6' },
  { action: 'remove', label: 'Retirer', icon: 'link_off', color: 'red-7' },
  { action: 'activate', label: 'Activer', icon: 'power', color: 'teal-7' },
]

const dlg = ref(false)
const curAction = ref('')
const newSn = ref('')
const profileId = ref('')
const planData = ref(null)
const planLoading = ref(false)
const planError = ref('')
const running = ref(false)

function openAction (action) {
  curAction.value = action
  newSn.value = ''
  profileId.value = ''
  planData.value = null
  planError.value = ''
  dlg.value = true
  loadPlan()
}

async function loadPlan () {
  planLoading.value = true; planError.value = ''
  try {
    const q = new URLSearchParams({ serial: props.serial, action: curAction.value })
    if (props.olt) q.set('olt', props.olt)
    if (newSn.value) q.set('new_sn', newSn.value)
    if (profileId.value) q.set('profileid', profileId.value)
    const r = await fetch(HUB_URL + '/olt/onu/plan?' + q.toString())
    if (!r.ok) throw new Error('plan ' + r.status)
    planData.value = await r.json()
  } catch (e) { planError.value = e.message || String(e); planData.value = null } finally { planLoading.value = false }
}

async function doRun () {
  if (!planData.value || !planData.value.can_run) return
  running.value = true
  try {
    // Clé d'idempotence par action confirmée (re-clic accidentel = pas de 2e tir côté hub, fenêtre 10 min).
    const key = (crypto.randomUUID ? crypto.randomUUID() : (Date.now() + '-' + Math.round(Math.random() * 1e9)))
    const body = { serial: props.serial, action: curAction.value, confirm: true, idempotencyKey: key }
    if (props.olt) body.olt = props.olt
    if (newSn.value) body.new_sn = newSn.value
    if (profileId.value) body.profileid = profileId.value
    const r = await fetch(HUB_URL + '/olt/onu/run', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) })
    const d = await r.json()
    if (d.ok) {
      Notify.create({ type: 'positive', message: (planData.value.label || 'Action') + ' — exécuté' + (d.idempotent ? ' (déjà fait)' : '') + (d.mirrored && d.mirrored.length ? ' · ' + d.mirrored.join(', ') : ''), timeout: 4000 })
      dlg.value = false
      emit('changed', { action: curAction.value, result: d })
    } else {
      Notify.create({ type: 'negative', message: (planData.value.label || 'Action') + ' — échec : ' + (d.net_error || d.error || 'inconnu'), timeout: 6000 })
    }
  } catch (e) { Notify.create({ type: 'negative', message: 'Erreur : ' + (e.message || e), timeout: 5000 }) } finally { running.value = false }
}
</script>

<style scoped>
.oa-target { font-size: 12.5px; display: flex; flex-direction: column; gap: 2px; }
.oa-target .oa-k { display: inline-block; min-width: 52px; color: #90a4ae; text-transform: uppercase; font-size: 10px; letter-spacing: .05em; }
.oa-effects { margin: 6px 0 0; padding-left: 18px; font-size: 12.5px; color: #37474f; }
.oa-warn { border-radius: 8px; }
.oa-warn-line { font-size: 12px; }
</style>
