<script setup>
/**
 * MonAujourdhui — accueil PERSONNEL adapté au rôle (cartes gated par capacité).
 *
 * Chiffres EXACTS (pas de proxy trompeur) : boîte via my-inbox-counts (boîte = conversations actives ;
 * sur moi = tickets suivis (follow)), interventions du jour groupées par statut + ÉTAT TERRAIN LIVE
 * (en route / sur place via /roster/geofence-states). Actions réelles (assistant NL pré-rempli, ⌘K, nouvelle vente).
 * Additif, monté en tête du tableau de bord.
 */
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { usePermissions } from 'src/composables/usePermissions'
import { useCommandPalette } from 'src/composables/useCommandPalette'
import { HUB_URL } from 'src/config/hub'
import { listDocs } from 'src/api/erp'

const router = useRouter()
const { can, userName, userEmail } = usePermissions()
const { openPalette } = useCommandPalette()

const TZ = 'America/Toronto'
const today = new Date().toLocaleDateString('en-CA', { timeZone: TZ })
const dateLabel = new Date().toLocaleDateString('fr-CA', { weekday: 'long', day: 'numeric', month: 'long', timeZone: TZ })

const loading = ref(true)
const inbox = ref(null) // { total, toTriage, mine }
const jobs = ref(null)  // { total, by, enRoute, onSite }

const firstName = computed(() => String(userName.value || '').trim().split(/\s+/)[0] || '')
const greeting = computed(() => {
  const h = Number(new Date().toLocaleString('en-US', { timeZone: TZ, hour: '2-digit', hour12: false }))
  const g = h < 12 ? 'Bonjour' : (h < 18 ? 'Bon après-midi' : 'Bonsoir')
  return firstName.value ? `${g}, ${firstName.value}` : g
})

const showJobs = computed(() => can('view_all_jobs'))
const showTickets = computed(() => can('view_all_tickets') || can('view_own_tickets'))
const showInbox = computed(() => can('view_clients'))
const canAssign = computed(() => can('view_all_jobs') || can('assign_jobs'))
const anyCard = computed(() => showJobs.value || showTickets.value || showInbox.value)

const STATUS = [
  { key: 'open', label: 'à faire', color: '#8b94a2' },
  { key: 'assigned', label: 'assignées', color: '#0e9c96' },
  { key: 'In Progress', label: 'en cours', color: '#3b6fb0' },
  { key: 'Completed', label: 'terminées', color: '#2e9e5b' },
]
const jobBreakdown = computed(() => {
  const by = (jobs.value && jobs.value.by) || {}
  return STATUS.map(s => ({ ...s, n: by[s.key] || 0 })).filter(s => s.n > 0)
})

// Heure courante (Québec) en minutes depuis minuit — pour détecter les arrivées EN RETARD sur les jobs du jour.
function nowEtMinutes () {
  try { const p = new Date().toLocaleTimeString('en-GB', { timeZone: TZ, hour12: false }); const a = p.split(':'); return (Number(a[0]) || 0) * 60 + (Number(a[1]) || 0) } catch (e) { return 0 }
}
async function hubGet (path) {
  try { const r = await fetch(HUB_URL + path, { headers: { 'Content-Type': 'application/json' } }); return r.ok ? await r.json() : null } catch { return null }
}

async function load () {
  loading.value = true
  const tasks = []
  if (showInbox.value || showTickets.value) {
    // Décompte EXACT côté serveur (get_count) — plus de rapatriement de 200 lignes filtrées côté client (plafonné/approx).
    tasks.push(hubGet('/conversations/my-inbox-counts?email=' + encodeURIComponent(userEmail.value || '')).then(d => {
      if (d) inbox.value = { inboxActive: d.inboxActive || 0, awaiting: d.awaiting || 0, mine: d.mine || 0, mineOverdue: d.mineOverdue || 0 }
    }))
  }
  if (showJobs.value) {
    tasks.push((async () => {
      const js = await listDocs('Dispatch Job', { filters: { scheduled_date: today }, fields: ['name', 'status', 'start_time'], limit: 300 }).catch(() => [])
      const by = {}; for (const j of (js || [])) by[j.status] = (by[j.status] || 0) + 1
      let enRoute = 0, onSite = 0, atRisk = 0, st = {}
      const names = (js || []).map(j => j.name).slice(0, 120)
      if (names.length) {
        const g = await hubGet('/roster/geofence-states?jobs=' + encodeURIComponent(names.join(',')))
        st = (g && g.states) || {}
        for (const k in st) { if (st[k] === 'en_route') enRoute++; else if (st[k] === 'on_site') onSite++ }
      }
      // EN RETARD : début prévu passé de > 20 min mais le géofence ne montre PAS le tech arrivé (ni parti) → retard d'arrivée.
      const nowMin = nowEtMinutes()
      for (const j of (js || [])) {
        if (j.status !== 'assigned' || !j.start_time) continue
        const s = String(j.start_time); const sm = (Number(s.slice(0, 2)) || 0) * 60 + (Number(s.slice(3, 5)) || 0)
        const state = st[j.name]
        if (state !== 'on_site' && state !== 'departed' && (nowMin - sm) > 20) atRisk++
      }
      jobs.value = { total: (js || []).length, by, enRoute, onSite, atRisk }
    })())
  }
  try { await Promise.all(tasks) } catch (e) { /* dégradé */ }
  loading.value = false
}
// Accueil = tableau VIVANT : rafraîchit les compteurs (en attente / en retard / interventions) toutes les 60 s et au
// retour sur l'onglet. dash() garde la valeur précédente pendant le refetch (pas de clignotement vers « … »).
let refreshTimer = null
function onVisible () { if (document.visibilityState === 'visible') load() }
onMounted(() => { load(); refreshTimer = setInterval(load, 60000); document.addEventListener('visibilitychange', onVisible) })
onUnmounted(() => { if (refreshTimer) clearInterval(refreshTimer); document.removeEventListener('visibilitychange', onVisible) })

const dash = (v) => (loading.value && v == null) ? '…' : (v == null ? '—' : v)
function allocate () { window.dispatchEvent(new CustomEvent('ops:assistant', { detail: { text: '' } })) } // ouvre l'Assistant (chat) vierge
</script>

<template>
  <div v-if="anyCard" class="mon-auj q-mb-md">
    <div class="mon-auj-hd">
      <div>
        <div class="mon-auj-hi">{{ greeting }}</div>
        <div class="mon-auj-day">{{ dateLabel }}</div>
      </div>
      <div class="mon-auj-acts">
        <button v-if="canAssign || showInbox" class="act act-pri" @click="allocate">
          <q-icon name="auto_awesome" size="17px" /> Assistant
        </button>
        <button v-if="showInbox" class="act" @click="router.push('/pipeline')">
          <q-icon name="sell" size="16px" /> Nouvelle vente
        </button>
        <button class="act act-ghost" @click="openPalette">
          <q-icon name="search" size="16px" /> Rechercher <span class="kbd">⌘K</span>
        </button>
      </div>
    </div>

    <div class="mon-auj-grid">
      <!-- Boîte de réception : conversations actives (vrai volume, store comms) -->
      <div v-if="showInbox" class="ma-card" @click="router.push('/communications')" role="button" tabindex="0">
        <div class="ma-top"><q-icon name="forum" size="20px" class="ma-ic" /><span>Boîte de réception</span><q-icon name="chevron_right" size="16px" class="ma-go" /></div>
        <div class="ma-big" :class="{ 'ma-attn': inbox && inbox.awaiting }">{{ dash(inbox && inbox.awaiting) }}</div>
        <div class="ma-sub">en attente de réponse<span v-if="inbox"> · {{ inbox.inboxActive }} active{{ inbox.inboxActive === 1 ? '' : 's' }}</span></div>
      </div>

      <!-- Tickets sur moi -->
      <div v-if="showTickets" class="ma-card" @click="router.push('/tickets')" role="button" tabindex="0">
        <div class="ma-top"><q-icon name="confirmation_number" size="20px" class="ma-ic" /><span>Tickets sur moi</span><q-icon name="chevron_right" size="16px" class="ma-go" /></div>
        <div class="ma-big">{{ dash(inbox && inbox.mine) }}</div>
        <div class="ma-sub"><span v-if="inbox && inbox.mineOverdue" class="ma-overdue">⚠ {{ inbox.mineOverdue }} en retard (&gt; 48 h)</span><span v-else>que je suis (ouverts)</span></div>
      </div>

      <!-- Interventions aujourd'hui + état terrain live -->
      <div v-if="showJobs" class="ma-card ma-wide" @click="router.push('/planification')" role="button" tabindex="0">
        <div class="ma-top"><q-icon name="event" size="20px" class="ma-ic" /><span>Interventions aujourd'hui</span><q-icon name="chevron_right" size="16px" class="ma-go" /></div>
        <div class="ma-row">
          <div class="ma-big">{{ dash(jobs && jobs.total) }}</div>
          <div class="ma-livewrap">
            <div v-if="jobs && (jobs.enRoute || jobs.onSite || jobs.atRisk)" class="ma-live">
              <span v-if="jobs.atRisk" class="ma-chip live" style="color:#d2483d;background:#d2483d1a"><span class="pulse" style="background:#d2483d"></span><b>{{ jobs.atRisk }}</b> en retard</span>
              <span v-if="jobs.enRoute" class="ma-chip live" style="color:#3b6fb0;background:#3b6fb01a"><span class="pulse" style="background:#3b6fb0"></span><b>{{ jobs.enRoute }}</b> en route</span>
              <span v-if="jobs.onSite" class="ma-chip live" style="color:#2e9e5b;background:#2e9e5b1a"><span class="pulse" style="background:#2e9e5b"></span><b>{{ jobs.onSite }}</b> sur place</span>
            </div>
            <div class="ma-chips">
              <span v-for="s in jobBreakdown" :key="s.key" class="ma-chip" :style="{ color: s.color, background: s.color + '14' }"><b>{{ s.n }}</b> {{ s.label }}</span>
              <span v-if="jobs && !jobBreakdown.length && !jobs.total" class="ma-sub">aucune intervention planifiée aujourd'hui</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.mon-auj-hd { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; margin: 2px 2px 14px; flex-wrap: wrap; }
.mon-auj-hi { font-size: 21px; font-weight: 730; letter-spacing: -.02em; color: var(--ops-text, #18202e); line-height: 1.15; }
.mon-auj-day { font-size: 13px; color: var(--ops-text-muted, #8b94a2); text-transform: capitalize; margin-top: 1px; }
.mon-auj-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.act { display: inline-flex; align-items: center; gap: 6px; font: inherit; font-size: 13px; font-weight: 600; padding: 8px 13px; border-radius: 9px;
  border: 1px solid var(--ops-border, #e7e2d8); background: var(--ops-surface, #fff); color: var(--ops-text, #18202e); cursor: pointer; transition: .13s; }
.act:hover { border-color: var(--ops-primary, #0e9c96); }
.act-pri { background: var(--ops-primary, #0e9c96); border-color: transparent; color: #fff; }
.act-pri:hover { filter: brightness(1.06); }
.act-ghost { color: var(--ops-text-muted, #57616f); }
.act .kbd { font-family: ui-monospace, Menlo, monospace; font-size: 10px; border: 1px solid currentColor; opacity: .5; border-radius: 4px; padding: 0 4px; margin-left: 2px; }
.mon-auj-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; }
.ma-card { background: var(--ops-surface, #fff); border: 1px solid var(--ops-border, #e7e2d8); border-radius: 12px; padding: 14px 16px;
  cursor: pointer; transition: border-color .13s, box-shadow .13s, transform .13s; box-shadow: 0 1px 2px rgba(24,32,46,.05); min-width: 0; }
.ma-card:hover { border-color: var(--ops-primary, #0e9c96); box-shadow: 0 8px 22px -14px rgba(24,32,46,.4); transform: translateY(-1px); }
.ma-card:focus-visible { outline: 2px solid var(--ops-primary, #0e9c96); outline-offset: 2px; }
.ma-wide { grid-column: span 2; }
.ma-top { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 640; color: var(--ops-text, #18202e); }
.ma-ic { color: var(--ops-primary, #0e9c96); }
.ma-go { margin-left: auto; color: var(--ops-text-muted, #8b94a2); }
.ma-big { font-size: 30px; font-weight: 760; letter-spacing: -.03em; line-height: 1.1; margin-top: 6px; color: var(--ops-text, #18202e); font-variant-numeric: tabular-nums; }
.ma-sub { font-size: 12px; color: var(--ops-text-muted, #8b94a2); margin-top: 2px; }
.ma-overdue { color: #d2483d; font-weight: 700; }
.ma-big.ma-attn { color: #be7a16; }
.ma-row { display: flex; align-items: center; gap: 18px; margin-top: 6px; }
.ma-livewrap { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ma-live, .ma-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ma-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; padding: 3px 9px; border-radius: 999px; font-variant-numeric: tabular-nums; }
.ma-chip b { font-weight: 800; }
.ma-chip.live { font-weight: 600; }
.pulse { width: 7px; height: 7px; border-radius: 50%; display: inline-block; animation: mapulse 1.6s ease-in-out infinite; }
@keyframes mapulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .pulse { animation: none; } }
@media (max-width: 700px) { .ma-wide { grid-column: span 1; } .mon-auj-acts { width: 100%; } }
</style>
