<template>
  <q-page padding>
    <div class="row items-center q-mb-md q-gutter-sm">
      <div class="text-h6 text-weight-bold">Rendez-vous clients</div>
      <q-space />
      <q-toggle v-model="onlyPending" label="À planifier seulement" dense />
      <q-btn flat dense round icon="refresh" :loading="loadingJobs" @click="loadJobs" />
    </div>

    <div class="row q-col-gutter-md">
      <!-- Worklist -->
      <div class="col-12 col-md-4">
        <q-list bordered separator class="rounded-borders">
          <q-item-label header>Jobs ({{ filteredJobs.length }})</q-item-label>
          <q-item v-for="j in filteredJobs" :key="j.name" clickable :active="sel && sel.name === j.name" active-class="bg-blue-1" @click="selectJob(j)">
            <q-item-section>
              <q-item-label class="text-weight-medium">{{ j.name }}</q-item-label>
              <q-item-label caption>{{ j.service_location || '—' }} · {{ j.duration_h || 1 }}h</q-item-label>
            </q-item-section>
            <q-item-section side>
              <q-badge :color="j.scheduled_date ? 'green' : 'orange'" :label="j.scheduled_date ? (j.scheduled_date.slice(5) + (j.start_time ? ' ' + j.start_time.slice(0,5) : '')) : 'à planifier'" />
            </q-item-section>
          </q-item>
          <q-item v-if="!filteredJobs.length"><q-item-section class="text-grey-6">Aucun job.</q-item-section></q-item>
        </q-list>
      </div>

      <!-- Booking panel -->
      <div class="col-12 col-md-8">
        <q-banner v-if="!sel" class="bg-grey-2">Sélectionne un job à gauche pour prendre rendez-vous.</q-banner>
        <q-card v-else flat bordered>
          <q-card-section class="q-pb-none">
            <div class="text-subtitle1 text-weight-bold">{{ sel.name }}</div>
            <div class="text-caption text-grey-7">{{ sel.service_location || '—' }} · durée {{ params.duration }}h · tech actuel: {{ sel.assigned_tech || '—' }}</div>
          </q-card-section>

          <q-card-section class="row q-col-gutter-sm items-end">
            <q-input dense outlined v-model="params.skill" label="Compétence requise" style="width:150px" />
            <q-input dense outlined v-model="params.zone" label="Zone" style="width:140px" />
            <q-input dense outlined type="number" step="0.5" v-model.number="params.duration" label="Durée (h)" style="width:100px" />
            <q-input dense outlined type="date" v-model="params.start" label="À partir du" style="width:160px" />
            <q-select dense outlined v-model="params.days" :options="[7,14,21]" label="Jours" emit-value map-options style="width:90px" />
          </q-card-section>

          <q-tabs v-model="mode" dense align="left" class="text-primary">
            <q-tab name="client" label="3 dispos du client" />
            <q-tab name="propose" label="Proposer des créneaux" />
          </q-tabs>
          <q-separator />

          <!-- 3 dispos client -->
          <q-card-section v-if="mode === 'client'">
            <div class="text-caption text-grey-7 q-mb-sm">Saisis les 3 disponibilités du client, en ordre de préférence. On place dans le 1er tenable.</div>
            <div v-for="(p, i) in prefs" :key="i" class="row items-center q-gutter-sm q-mb-xs">
              <q-badge color="grey-7">{{ i + 1 }}</q-badge>
              <q-input dense outlined type="date" v-model="p.date" style="width:160px" />
              <q-input dense outlined type="time" v-model="p.start" style="width:120px" />
            </div>
            <q-btn unelevated color="primary" icon="search" label="Vérifier" :loading="fitting" class="q-mt-sm" @click="doFit" />

            <div v-if="fit" class="q-mt-md">
              <q-banner v-if="fit.chosen" dense rounded class="bg-green-1 text-green-9">
                ✅ Choix <b>#{{ fit.chosen.rank }}</b> retenu : {{ frDate(fit.chosen.date) }} {{ fit.chosen.start }}–{{ fit.chosen.end }} · {{ fit.chosen.tech_name }}
                <q-btn unelevated color="positive" icon="check" label="Confirmer" class="q-ml-md" :loading="confirming" @click="confirm(fit.chosen)" />
              </q-banner>
              <q-banner v-else dense rounded class="bg-orange-1 text-orange-9">
                ⚠️ Aucune des 3 dispos n'est tenable. Créneaux proposés :
                <div class="q-mt-xs">
                  <q-chip v-for="(s, k) in fit.proposed" :key="k" dense>{{ frDate(s.date) }} {{ s.start }} ({{ s.available }} dispo)</q-chip>
                  <span v-if="!fit.proposed.length" class="text-grey-7">aucun — élargis la période ou la compétence.</span>
                </div>
                <div class="text-caption q-mt-xs">Passe à « Proposer des créneaux » pour en assigner un.</div>
              </q-banner>
            </div>
          </q-card-section>

          <!-- Proposer -->
          <q-card-section v-else>
            <q-btn unelevated color="primary" icon="search" label="Trouver des créneaux" :loading="finding" @click="findSlots" />
            <div v-if="slots.length" class="q-mt-md">
              <div class="text-caption text-grey-7 q-mb-xs">{{ slots.length }} créneaux — clique pour sélectionner :</div>
              <div class="slot-grid">
                <div v-for="(s, k) in slots" :key="k" class="slot" :class="{ on: chosen === s }" @click="chosen = s">
                  <div class="text-weight-medium">{{ frDate(s.date) }}</div>
                  <div>{{ s.start }}–{{ s.end }}</div>
                  <div class="text-caption text-grey-7">{{ s.tech_name }}</div>
                </div>
              </div>
              <q-btn v-if="chosen" unelevated color="positive" icon="check" label="Confirmer ce créneau" class="q-mt-md" :loading="confirming" @click="confirm(chosen)" />
            </div>
            <div v-else-if="searched" class="text-grey-6 q-mt-md">Aucun créneau — élargis la période, la zone ou la compétence (le roster doit être publié).</div>
          </q-card-section>
        </q-card>
      </div>
    </div>
  </q-page>
</template>

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

const $q = useQuasar()
const jobs = ref([])
const onlyPending = ref(true)
const loadingJobs = ref(false)
const sel = ref(null)
const mode = ref('client')
const params = reactive({ skill: '', zone: '', duration: 1, start: todayISO(), days: 14 })
const prefs = ref([{ date: '', start: '' }, { date: '', start: '' }, { date: '', start: '' }])
const fit = ref(null); const fitting = ref(false)
const slots = ref([]); const chosen = ref(null); const finding = ref(false); const searched = ref(false)
const confirming = ref(false)

function todayISO () { return new Date().toLocaleDateString('en-CA', { timeZone: 'America/Toronto' }) }
const FR_DOW = ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam']
function frDate (iso) { if (!iso) return ''; const [y, m, d] = iso.split('-').map(Number); const dt = new Date(Date.UTC(y, m - 1, d)); return FR_DOW[dt.getUTCDay()] + ' ' + iso.slice(8) + '/' + iso.slice(5, 7) }

const filteredJobs = computed(() => onlyPending.value ? jobs.value.filter(j => !j.scheduled_date || j.booking_status !== 'Confirmé') : jobs.value)

async function loadJobs () { loadingJobs.value = true; try { jobs.value = (await roster.bookJobs()).jobs || [] } catch (e) { err(e) } finally { loadingJobs.value = false } }
function selectJob (j) { sel.value = j; params.duration = Number(j.duration_h) || 1; fit.value = null; slots.value = []; chosen.value = null; searched.value = false }

async function doFit () {
  const valid = prefs.value.filter(p => p.date && p.start)
  if (!valid.length) { $q.notify({ type: 'warning', message: 'Saisis au moins une dispo' }); return }
  fitting.value = true
  try { fit.value = await roster.bookFit({ skill: params.skill, zone: params.zone, duration: params.duration, prefs: valid }) } catch (e) { err(e) } finally { fitting.value = false }
}
async function findSlots () {
  finding.value = true; searched.value = true; chosen.value = null
  try { slots.value = (await roster.bookSlots({ skill: params.skill, zone: params.zone, duration: params.duration, start: params.start, days: params.days, limit: 40 })).slots || [] } catch (e) { err(e) } finally { finding.value = false }
}
async function confirm (s) {
  confirming.value = true
  try {
    const prefsUsed = prefs.value.filter(p => p.date && p.start)
    const r = await roster.bookConfirm({ job: sel.value.name, tech: s.tech, date: s.date, start: s.start, duration: params.duration, prefs: prefsUsed })
    if (r.ok === false) { err(new Error(r.error || 'échec')); return }
    $q.notify({ type: 'positive', message: `RDV confirmé : ${frDate(s.date)} ${s.start} · ${s.tech_name || s.tech}` })
    await loadJobs(); const cur = jobs.value.find(j => j.name === sel.value.name); sel.value = cur || null; fit.value = null; slots.value = []; chosen.value = null
  } catch (e) { err(e) } finally { confirming.value = false }
}
function err (e) { $q.notify({ type: 'negative', message: '' + (e.message || e) }) }

onMounted(loadJobs)
</script>

<style scoped>
.slot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 6px; }
.slot { border: 1px solid #e0e0e0; border-radius: 6px; padding: 6px 8px; cursor: pointer; font-size: 12px; text-align: center; }
.slot:hover { border-color: #1976d2; }
.slot.on { background: #c8e6c9; border-color: #2e7d32; }
</style>
