<!--
  GpsDevicesDialog — vue « appareil GPS → technicien » (sens INVERSE de l'assignation du popover tech en vue Semaine).
  On voit tous les appareils Traccar, lesquels sont NON ASSOCIÉS, et on assigne un appareil à un tech en un clic.
  Autonome : charge son roster (roster.listTraccarDevicesRoster) + les techs à l'ouverture. Réutilise TechSelect.
-->
<template>
  <q-dialog :model-value="modelValue" @update:model-value="$emit('update:modelValue', $event)" :maximized="$q.screen.lt.sm">
    <q-card style="width:720px;max-width:96vw" class="column no-wrap">
      <q-card-section class="row items-center q-pb-sm">
        <q-icon name="gps_fixed" size="22px" color="teal-7" class="q-mr-sm" />
        <div class="col">
          <div class="text-subtitle1 text-weight-bold">Appareils GPS</div>
          <div class="text-caption text-grey-6">{{ devices.length }} appareil(s) · {{ unassignedCount }} non associé(s)<span v-if="dupCount"> · <span class="text-orange-8">{{ dupCount }} en double</span></span></div>
        </div>
        <q-toggle v-model="onlyUnassigned" dense size="sm" label="Non associés" color="teal-7" class="q-mr-sm" />
        <q-btn flat round dense icon="refresh" :loading="loading" @click="load"><q-tooltip>Rafraîchir</q-tooltip></q-btn>
        <q-btn flat round dense icon="close" v-close-popup />
      </q-card-section>
      <q-separator />
      <q-card-section class="col scroll q-pa-none">
        <q-table flat dense :rows="shown" :columns="cols" row-key="id" :pagination="{ rowsPerPage: 0 }"
          hide-bottom :loading="loading" no-data-label="Aucun appareil Traccar">
          <template #body-cell-status="p">
            <q-td :props="p"><q-icon name="circle" size="10px" :color="p.row.status === 'online' ? 'green-6' : (p.row.status === 'offline' ? 'grey-5' : 'orange-6')" /><q-tooltip>{{ p.row.status }}</q-tooltip></q-td>
          </template>
          <template #body-cell-device="p">
            <q-td :props="p"><div class="text-weight-medium">{{ p.row.name }}</div><div class="text-caption text-grey-6">{{ p.row.unique_id }}</div></q-td>
          </template>
          <template #body-cell-seen="p">
            <q-td :props="p"><span class="text-caption">{{ relTime(p.row.last_update) }}</span></q-td>
          </template>
          <template #body-cell-tech="p">
            <q-td :props="p" style="min-width:220px">
              <TechSelect :model-value="p.row.assigned[0] ? p.row.assigned[0].id : null" :options="techOpts"
                :label="p.row.unassigned ? 'Associer à…' : 'Changer…'" style="min-width:200px"
                @update:model-value="v => assign(p.row, v)" />
              <div v-if="p.row.duplicate" class="text-caption text-orange-8">⚠ {{ p.row.assigned.map(a => a.name).join(', ') }}</div>
            </q-td>
          </template>
        </q-table>
      </q-card-section>
    </q-card>
  </q-dialog>
</template>

<script setup>
import { ref, computed, watch } from 'vue'
import { useQuasar } from 'quasar'
import * as roster from 'src/api/roster'
import TechSelect from './TechSelect.vue'

const props = defineProps({ modelValue: { type: Boolean, default: false } })
defineEmits(['update:modelValue'])
const $q = useQuasar()

const devices = ref([])
const techs = ref([])
const loading = ref(false)
const onlyUnassigned = ref(false)
const busy = ref(null)

const cols = [
  { name: 'status', label: '', field: 'status', align: 'center' },
  { name: 'device', label: 'Appareil', field: 'name', align: 'left' },
  { name: 'seen', label: 'Dernier signal', field: 'last_update', align: 'left' },
  { name: 'tech', label: 'Technicien', field: 'tech', align: 'left' },
]
const techOpts = computed(() => (techs.value || []).map(t => ({ label: t.name + ((t.skills || []).length ? ' · ' + t.skills.slice(0, 3).join(', ') : ''), value: t.id })))
const shown = computed(() => onlyUnassigned.value ? devices.value.filter(d => d.unassigned) : devices.value)
const unassignedCount = computed(() => devices.value.filter(d => d.unassigned).length)
const dupCount = computed(() => devices.value.filter(d => d.duplicate).length)

function relTime (iso) {
  if (!iso) return 'jamais'
  const ms = Date.now() - Date.parse(iso); if (!isFinite(ms)) return '—'
  const m = Math.round(ms / 60000); if (m < 1) return "à l'instant"; if (m < 60) return 'il y a ' + m + ' min'
  const h = Math.round(m / 60); if (h < 24) return 'il y a ' + h + ' h'
  return 'il y a ' + Math.round(h / 24) + ' j'
}

async function load () {
  loading.value = true
  try {
    const [dr, tr] = await Promise.all([roster.listTraccarDevicesRoster(), roster.listTechnicians().catch(() => [])])
    devices.value = (dr && dr.devices) || []
    techs.value = Array.isArray(tr) ? tr : ((tr && tr.technicians) || [])
  } catch (e) { $q.notify({ type: 'negative', message: 'Chargement GPS : ' + (e.message || e), timeout: 3000 }) } finally { loading.value = false }
}
async function assign (row, techId) {
  if (busy.value) return
  busy.value = row.id
  try {
    await roster.assignTraccarDevice(row.id, techId || '')
    const t = (techs.value || []).find(x => x.id === techId)
    $q.notify({ type: 'positive', message: techId ? ('« ' + row.name +' » → ' + ((t && t.name) || techId)) : ('« ' + row.name + ' » dissocié'), timeout: 1800 })
    await load()
  } catch (e) { $q.notify({ type: 'negative', message: 'Assignation : ' + (e.message || e), timeout: 3000 }) } finally { busy.value = null }
}

watch(() => props.modelValue, (o) => { if (o) load() })
</script>
