<!--
  GeofenceTimeline — suivi terrain (géofencing GPS) façon suivi de colis : Assigné → En route → Arrivé → Reparti.
  Module RÉUTILISABLE extrait du volet jobDetail (PlanificationPage). Autonome : il charge lui-même la timeline
  via roster.jobGeofence(name) si aucun objet `geofence` n'est fourni. Aucune dépendance à l'état de la page.
  N'affiche rien si le job n'a pas d'état de géofence (pas de bruit).
-->
<template>
  <div v-if="gf && gf.state" class="jd-geo">
    <div class="text-subtitle2 row items-center q-mb-xs"><q-icon name="my_location" size="18px" class="q-mr-xs" color="teal-7" /> Suivi terrain (GPS)</div>
    <div class="jd-geo-track">
      <div v-for="s in timeline" :key="s.k" class="jd-geo-step" :class="{ done: s.done, current: s.current }">
        <div class="jd-geo-ic"><q-icon :name="s.icon" size="15px" /></div>
        <div class="jd-geo-lbl">{{ s.label }}<span v-if="s.at" class="jd-geo-at">{{ s.at }}</span></div>
      </div>
    </div>
    <!-- Véhicule Traccar figé AU MOMENT du passage (reste exact même si le tech change de véhicule un autre jour). -->
    <div v-if="vehicle" class="jd-geo-veh"><q-icon name="directions_car" size="12px" /> Véhicule : {{ vehicle }}</div>
    <!-- Réconciliation : autres véhicules réellement sur place → assistant / mauvaise affectation. Suggestions, confirmées (jamais auto). -->
    <div v-if="onsiteSug.length" class="jd-geo-sug">
      <div v-for="(s, i) in onsiteSug" :key="i" class="jd-sug">
        <div class="jd-sug-note"><q-icon :name="s.type === 'assistant' ? 'group_add' : s.type === 'misassignment' ? 'sync_problem' : 'help_outline'" size="13px" :color="s.type === 'misassignment' ? 'deep-orange-7' : 'teal-7'" /> {{ s.note }}</div>
        <div class="jd-sug-acts">
          <q-btn v-if="s.type === 'assistant'" dense flat no-caps size="sm" color="teal-8" icon="group_add" label="Ajouter comme assistant" :loading="busy === s.deviceId" @click="addAssist(s)" />
          <q-btn v-else-if="s.type === 'misassignment' && !s.techId" dense flat no-caps size="sm" color="deep-orange-8" icon="directions_car" label="Assigner ce véhicule au tech" :loading="busy === s.deviceId" @click="fixVehicle(s)" />
          <q-btn dense flat no-caps size="sm" color="grey-6" label="Ignorer" @click="ignore(s)" />
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { useQuasar } from 'quasar'
import * as roster from 'src/api/roster'
const $q = useQuasar()

const props = defineProps({
  name: { type: String, default: '' }, // docname du Dispatch Job
  geofence: { type: Object, default: null }, // objet déjà chargé { state, events } — sinon on le fetch
})

const GEO_STEPS = [
  { k: 'assigned', label: 'Assigné', icon: 'assignment_ind' },
  { k: 'en_route', label: 'En route', icon: 'directions_car' },
  { k: 'on_site', label: 'Arrivé sur place', icon: 'location_on' },
  { k: 'departed', label: 'Reparti', icon: 'check_circle' },
]

const loaded = ref(null)
const gf = computed(() => props.geofence || loaded.value)

const timeline = computed(() => {
  const g = gf.value; const events = (g && g.events) || []
  const atOf = (k) => { const e = [...events].reverse().find(x => x.status === k); return e ? new Date(e.at).toLocaleTimeString('fr-CA', { hour: '2-digit', minute: '2-digit', timeZone: 'America/Toronto' }) : null }
  const order = { assigned: 0, en_route: 1, on_site: 2, departed: 3 }
  const curIdx = order[(g && g.state) || 'assigned'] ?? 0
  return GEO_STEPS.map((s, i) => ({ ...s, at: s.k === 'assigned' ? null : atOf(s.k), done: i <= curIdx, current: i === curIdx }))
})

// Véhicule utilisé lors du passage : device figé sur le suivi (rec.device), sinon dernier événement portant un deviceName.
const vehicle = computed(() => {
  const g = gf.value; if (!g) return ''
  if (g.device && g.device.deviceName) return g.device.deviceName
  const ev = [...((g && g.events) || [])].reverse().find(e => e.deviceName)
  return (ev && ev.deviceName) || ''
})

// Réconciliation véhicule : suggestions (assistant / mauvaise affectation) issues des traces GPS. Confirmées, jamais auto.
const onsite = ref(null); const busy = ref(null)
const onsiteSug = computed(() => (onsite.value && onsite.value.suggestions) || [])
async function drop (s) { try { await roster.onsiteDismiss(props.name, s.deviceId) } catch (e) {} if (onsite.value) onsite.value = { ...onsite.value, suggestions: onsiteSug.value.filter(x => x.deviceId !== s.deviceId) } }
async function addAssist (s) {
  busy.value = s.deviceId
  try { await roster.addAssistant(props.name, { tech_id: s.techDoc || s.techId, tech_name: s.techName }); await drop(s); $q.notify({ type: 'positive', message: (s.techName || 'Technicien') + ' ajouté comme assistant' }) }
  catch (e) { $q.notify({ type: 'negative', message: e.message || 'Échec' }) } finally { busy.value = null }
}
async function fixVehicle (s) {
  busy.value = s.deviceId
  try { await roster.setTechTraccarDevice(s.assignedTech, s.deviceId); await drop(s); $q.notify({ type: 'positive', message: 'Véhicule du tech mis à jour' }) }
  catch (e) { $q.notify({ type: 'negative', message: e.message || 'Échec' }) } finally { busy.value = null }
}
async function ignore (s) { await drop(s) }

async function load () {
  if (!props.name) return
  if (!props.geofence) { try { loaded.value = await roster.jobGeofence(props.name) } catch (e) { loaded.value = null } }
  // Scan des véhicules sur place seulement s'il y a un suivi terrain (rec de géofence existe) — évite un scan inutile.
  if (gf.value && gf.value.state) { try { onsite.value = await roster.jobOnsite(props.name) } catch (e) { onsite.value = null } }
}
watch(() => props.name, () => { loaded.value = null; onsite.value = null; load() })
onMounted(load)
</script>

<style scoped>
.jd-geo { margin-top: 12px; padding: 10px 8px; border: 1px solid #d6eeeb; background: #f3fbfa; border-radius: 8px; }
.jd-geo-track { display: flex; align-items: flex-start; }
.jd-geo-step { flex: 1; text-align: center; position: relative; }
.jd-geo-step::before { content: ''; position: absolute; top: 13px; left: -50%; width: 100%; height: 2px; background: #cfe3e0; z-index: 0; }
.jd-geo-step:first-child::before { display: none; }
.jd-geo-step.done::before { background: #26a69a; }
.jd-geo-ic { position: relative; z-index: 1; width: 28px; height: 28px; margin: 0 auto; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: #e0e0e0; color: #fff; }
.jd-geo-step.done .jd-geo-ic { background: #26a69a; }
.jd-geo-step.current .jd-geo-ic { box-shadow: 0 0 0 3px rgba(38,166,154,.3); }
.jd-geo-lbl { font-size: 10.5px; color: #607d8b; margin-top: 3px; line-height: 1.25; }
.jd-geo-step.done .jd-geo-lbl { color: #37474f; font-weight: 600; }
.jd-geo-at { display: block; font-size: 10px; color: #26a69a; font-weight: 700; }
.jd-geo-veh { margin-top: 8px; font-size: 11px; color: #37474f; font-weight: 600; display: flex; align-items: center; gap: 4px; }
.jd-geo-sug { margin-top: 8px; border-top: 1px dashed #cfe3e0; padding-top: 6px; }
.jd-sug { margin-top: 4px; }
.jd-sug-note { font-size: 11px; color: #37474f; display: flex; align-items: center; gap: 4px; line-height: 1.35; }
.jd-sug-acts { display: flex; flex-wrap: wrap; gap: 2px; margin-top: 2px; }
</style>
