<!--
  TechDevicePage — full device detail view for a tech at /j/device/:serial.

  Reached from TechScanPage's "Détails" button (router `{ name: 'tech-device' }`)
  or directly via URL when a tech pastes a serial they got off the phone.

  Unlike the field-app predecessor, this page surfaces EVERY entity touching
  the scanned device so the tech has full context on site:

    ┌ Équipement ────────┐    serial, MAC, brand, model, firmware, status
    ├ Client ────────────┤    customer name + link to ClientDetailPage (ops)
    ├ Adresse de service ┤    address, city, postal, connection type, OLT port
    ├ Abonnement actif ──┤    subscription status, plan, billing window
    ├ Tickets ouverts ───┤    open Issues at this Service Location
    ├ Interventions ─────┤    upcoming Dispatch Jobs at this Service Location
    └ Info OLT ──────────┘    frame/slot/port/ontid if this is an ONT

  See docs/features/vision-ocr.md §10 for the full relationship map. The data
  loads lazily (equipment first, then location + related entities in
  parallel) — if the network drops halfway, the first card still renders.

  All reads use `listDocs` / `getDoc` from src/api/erp (same proxy-with-
  token pattern as the rest of the ops app). Writes (customer re-link)
  use `updateDoc` and bypass the offline queue intentionally — re-linking
  is a deliberate, visible operation that needs to fail fast.
-->
<template>
  <q-page padding class="tech-device-page tech-surface">
    <q-btn flat icon="arrow_back" label="Retour" @click="$router.back()" class="q-mb-sm" />

    <q-spinner v-if="loading" size="lg" class="block q-mx-auto q-mt-xl" />

    <template v-if="device">
      <!-- Core equipment card -->
      <q-card class="q-mb-md">
        <q-card-section>
          <div class="row items-center q-mb-sm">
            <q-badge :color="statusColor" class="q-mr-sm" :label="device.status || 'Inconnu'" />
            <div class="text-h6">{{ device.equipment_type || 'Équipement' }}</div>
          </div>
          <q-list dense>
            <q-item>
              <q-item-section avatar><q-icon name="tag" /></q-item-section>
              <q-item-section>
                <q-item-label caption>Numéro de série</q-item-label>
                <q-item-label class="mono">{{ device.serial_number }}</q-item-label>
              </q-item-section>
            </q-item>
            <q-item v-if="device.mac_address">
              <q-item-section avatar><q-icon name="router" /></q-item-section>
              <q-item-section>
                <q-item-label caption>MAC</q-item-label>
                <q-item-label class="mono">{{ device.mac_address }}</q-item-label>
              </q-item-section>
            </q-item>
            <q-item v-if="device.brand || device.model">
              <q-item-section avatar><q-icon name="devices" /></q-item-section>
              <q-item-section>
                <q-item-label caption>Marque / Modèle</q-item-label>
                <q-item-label>{{ device.brand }} {{ device.model }}</q-item-label>
              </q-item-section>
            </q-item>
            <q-item v-if="device.ip_address">
              <q-item-section avatar><q-icon name="language" /></q-item-section>
              <q-item-section>
                <q-item-label caption>IP</q-item-label>
                <q-item-label class="mono">{{ device.ip_address }}</q-item-label>
              </q-item-section>
            </q-item>
            <q-item v-if="device.firmware_version">
              <q-item-section avatar><q-icon name="system_update" /></q-item-section>
              <q-item-section>
                <q-item-label caption>Firmware</q-item-label>
                <q-item-label>{{ device.firmware_version }}</q-item-label>
              </q-item-section>
            </q-item>
          </q-list>
        </q-card-section>
      </q-card>

      <!-- Customer card -->
      <q-card class="q-mb-md">
        <q-card-section>
          <div class="text-subtitle1 q-mb-sm">
            <q-icon name="person" class="q-mr-xs" /> Compte client
          </div>
          <div v-if="device.customer" class="text-body1">
            {{ device.customer_name || device.customer }}
          </div>
          <div v-else class="text-grey">Aucun client associé</div>

          <q-input v-model="customerSearch" label="Rechercher un client" outlined dense class="q-mt-sm"
            @update:model-value="searchCustomer" debounce="400">
            <template v-slot:append><q-icon name="search" /></template>
          </q-input>
          <q-list v-if="customerResults.length > 0" dense bordered class="q-mt-xs" style="max-height: 200px; overflow: auto">
            <q-item v-for="c in customerResults" :key="c.name" clickable @click="linkToCustomer(c)">
              <q-item-section>
                <q-item-label>{{ c.customer_name }}</q-item-label>
                <q-item-label caption>{{ c.name }}</q-item-label>
              </q-item-section>
            </q-item>
          </q-list>
        </q-card-section>
      </q-card>

      <!-- Service Location card -->
      <q-card v-if="location" class="q-mb-md">
        <q-card-section>
          <div class="text-subtitle1 q-mb-sm">
            <q-icon name="place" class="q-mr-xs" /> Adresse de service
          </div>
          <div class="text-body1">{{ location.location_name || location.name }}</div>
          <div class="text-caption q-mt-xs">
            {{ location.address_line }}<br>
            {{ location.city }} {{ location.postal_code }}
          </div>
          <div v-if="location.connection_type" class="text-caption text-grey q-mt-xs">
            <q-icon name="cable" size="xs" /> Connexion: {{ location.connection_type }}
          </div>
          <div v-if="location.contact_phone" class="text-caption q-mt-xs">
            <q-icon name="phone" size="xs" /> {{ location.contact_phone }}
          </div>
          <q-btn v-if="location.latitude && location.longitude"
            flat dense size="sm" icon="directions" label="Navigation GPS"
            class="q-mt-sm"
            @click="openGps(location)" />
        </q-card-section>
      </q-card>

      <!-- Active subscription card -->
      <q-card v-if="subscription" class="q-mb-md">
        <q-card-section>
          <div class="text-subtitle1 q-mb-sm">
            <q-icon name="receipt_long" class="q-mr-xs" /> Abonnement
          </div>
          <q-badge :color="subscription.status === 'Active' ? 'green' : 'orange'" :label="subscription.status" class="q-mb-xs" />
          <div class="text-caption">Depuis le {{ subscription.start_date }}</div>
          <div v-if="subscription.current_invoice_end" class="text-caption text-grey">
            Prochaine facturation: {{ subscription.current_invoice_end }}
          </div>
        </q-card-section>
      </q-card>

      <!-- Open tickets at this location -->
      <q-card v-if="tickets.length" class="q-mb-md">
        <q-card-section>
          <div class="text-subtitle1 q-mb-sm">
            <q-icon name="confirmation_number" class="q-mr-xs" />
            Tickets ouverts ({{ tickets.length }})
          </div>
          <q-list separator>
            <q-item v-for="t in tickets" :key="t.name">
              <q-item-section>
                <q-item-label>
                  <q-badge :color="priorityColor(t.priority)" :label="t.priority || 'Normal'" class="q-mr-xs" />
                  {{ t.subject }}
                </q-item-label>
                <q-item-label caption>
                  {{ t.name }} · Ouvert le {{ t.opening_date }}
                </q-item-label>
              </q-item-section>
              <q-item-section side>
                <q-badge outline :color="t.status === 'Open' ? 'red' : 'orange'" :label="t.status" />
              </q-item-section>
            </q-item>
          </q-list>
        </q-card-section>
      </q-card>

      <!-- Upcoming Dispatch Jobs at this location -->
      <q-card v-if="upcomingJobs.length" class="q-mb-md">
        <q-card-section>
          <div class="text-subtitle1 q-mb-sm">
            <q-icon name="schedule" class="q-mr-xs" />
            Interventions prévues ({{ upcomingJobs.length }})
          </div>
          <q-list separator>
            <q-item v-for="j in upcomingJobs" :key="j.name" clickable
              @click="$router.push({ name: 'tech-job', params: { name: j.name } })">
              <q-item-section>
                <q-item-label>{{ j.subject || j.job_type || j.name }}</q-item-label>
                <q-item-label caption>
                  {{ j.scheduled_date }} · {{ j.technician || 'Non assigné' }}
                </q-item-label>
              </q-item-section>
              <q-item-section side>
                <q-badge :color="j.status === 'Planned' ? 'blue' : 'grey'" :label="j.status" />
              </q-item-section>
            </q-item>
          </q-list>
        </q-card-section>
      </q-card>

      <!-- OLT provisioning info (ops-specific — 'olt_*' fields, not 'custom_olt_*') -->
      <q-card v-if="device.olt_name" class="q-mb-md">
        <q-card-section>
          <div class="text-subtitle1 q-mb-sm">
            <q-icon name="lan" class="q-mr-xs" /> Info OLT
          </div>
          <q-list dense>
            <q-item>
              <q-item-section>
                <q-item-label caption>OLT</q-item-label>
                <q-item-label>{{ device.olt_name }} <span class="text-grey">({{ device.olt_ip }})</span></q-item-label>
              </q-item-section>
            </q-item>
            <q-item v-if="device.olt_frame !== undefined">
              <q-item-section>
                <q-item-label caption>Port</q-item-label>
                <q-item-label class="mono">
                  {{ device.olt_frame }}/{{ device.olt_slot }}/{{ device.olt_port }} · ONT {{ device.olt_ontid }}
                </q-item-label>
              </q-item-section>
            </q-item>
          </q-list>
        </q-card-section>
      </q-card>
    </template>

    <div v-if="!loading && !device" class="text-center text-grey q-mt-xl">
      <q-icon name="search_off" size="48px" class="block q-mx-auto q-mb-sm" />
      Équipement non trouvé pour <span class="mono">{{ props.serial }}</span>
    </div>
  </q-page>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { listDocs, getDoc, updateDoc } from 'src/api/erp'
import { Notify } from 'quasar'

const props = defineProps({ serial: String })

const loading = ref(true)
const device = ref(null)
const location = ref(null)
const subscription = ref(null)
const tickets = ref([])
const upcomingJobs = ref([])

const customerSearch = ref('')
const customerResults = ref([])

const statusColor = computed(() => {
  const s = device.value?.status
  if (s === 'Actif') return 'green'
  if (s === 'Défectueux' || s === 'Perdu') return 'red'
  return 'grey'
})

function priorityColor (p) {
  if (p === 'High' || p === 'Urgent') return 'red'
  if (p === 'Medium') return 'orange'
  return 'grey'
}

/**
 * Primary lookup: resolve the :serial route param to a Service Equipment
 * name, then fetch the full doc + every related entity in parallel.
 *
 * Tolerant of failures: if any related fetch blows up (RLS, race, stale
 * foreign key), we swallow and render the main card anyway. The tech
 * needs to see the device even if e.g. the Dispatch Job fetch times out.
 */
async function loadDevice () {
  loading.value = true
  try {
    // Step 1: find the Service Equipment name by any of 3 identifiers
    let eqName = null
    const results = await listDocs('Service Equipment', {
      filters: { serial_number: props.serial },
      fields: ['name'],
      limit: 1,
    })
    if (results.length > 0) {
      eqName = results[0].name
    } else {
      const byBarcode = await listDocs('Service Equipment', {
        filters: { barcode: props.serial },
        fields: ['name'],
        limit: 1,
      })
      if (byBarcode.length > 0) eqName = byBarcode[0].name
    }

    if (!eqName) { loading.value = false; return }

    // Step 2: fetch full device doc
    device.value = await getDoc('Service Equipment', eqName)

    // Step 3: fan out to related entities. Run in parallel — each one is
    // independently optional so a single failure doesn't cascade.
    const promises = []
    if (device.value.service_location) {
      promises.push(loadLocation(device.value.service_location))
      promises.push(loadTicketsAt(device.value.service_location))
      promises.push(loadJobsAt(device.value.service_location))
    }
    if (device.value.customer) {
      promises.push(loadActiveSubscription(device.value.customer))
    }
    await Promise.allSettled(promises)
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur chargement: ' + e.message })
  } finally {
    loading.value = false
  }
}

async function loadLocation (locationName) {
  try {
    location.value = await getDoc('Service Location', locationName)
  } catch { /* stale FK — ignore */ }
}

async function loadActiveSubscription (customerId) {
  try {
    // Subscriptions are tied to the customer, not the location. We show
    // the most recent active one — multi-location customers may have
    // several and the UI only picks the freshest for the chip.
    const subs = await listDocs('Subscription', {
      filters: { party_type: 'Customer', party: customerId, status: 'Active' },
      fields: ['name', 'status', 'start_date', 'current_invoice_end'],
      limit: 1,
      orderBy: 'start_date desc',
    })
    if (subs.length) subscription.value = subs[0]
  } catch { /* no subscription → card hidden */ }
}

async function loadTicketsAt (locationName) {
  try {
    tickets.value = await listDocs('Issue', {
      filters: { service_location: locationName, status: ['in', ['Open', 'In Progress', 'On Hold']] },
      fields: ['name', 'subject', 'status', 'priority', 'opening_date'],
      limit: 10,
      orderBy: 'opening_date desc',
    })
  } catch { tickets.value = [] }
}

async function loadJobsAt (locationName) {
  try {
    upcomingJobs.value = await listDocs('Dispatch Job', {
      filters: {
        service_location: locationName,
        status: ['in', ['Planned', 'Scheduled', 'En Route', 'In Progress']],
      },
      fields: ['name', 'subject', 'job_type', 'status', 'scheduled_date', 'technician'],
      limit: 5,
      orderBy: 'scheduled_date asc',
    })
  } catch { upcomingJobs.value = [] }
}

async function searchCustomer (text) {
  if (!text || text.length < 2) { customerResults.value = []; return }
  try {
    customerResults.value = await listDocs('Customer', {
      filters: { customer_name: ['like', '%' + text + '%'] },
      fields: ['name', 'customer_name'],
      limit: 10,
    })
  } catch { customerResults.value = [] }
}

async function linkToCustomer (customer) {
  try {
    await updateDoc('Service Equipment', device.value.name, { customer: customer.name })
    device.value.customer = customer.name
    device.value.customer_name = customer.customer_name
    customerResults.value = []
    customerSearch.value = ''
    // Re-load subscription for the new customer
    subscription.value = null
    loadActiveSubscription(customer.name)
    Notify.create({ type: 'positive', message: 'Lié à ' + customer.customer_name })
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur: ' + e.message })
  }
}

function openGps (loc) {
  const dest = loc.latitude && loc.longitude
    ? `${loc.latitude},${loc.longitude}`
    : encodeURIComponent(`${loc.address_line || ''} ${loc.city || ''}`)
  window.open(`https://www.google.com/maps/dir/?api=1&destination=${dest}`, '_blank')
}

onMounted(loadDevice)
</script>

<style lang="scss" scoped>
.tech-device-page {
  padding-bottom: 80px !important;  /* TechLayout bottom tabs */
}
.mono {
  font-family: monospace;
}
</style>
