<template>
  <div class="ops-card q-mb-md">
    <q-card-section>
      <div class="row items-center q-gutter-xs">
        <q-icon name="hub" color="primary" size="20px" />
        <div class="text-subtitle2">Départements (omnichannel)</div>
        <q-space />
        <q-btn v-if="dirty" unelevated no-caps dense color="primary" icon="save"
          label="Enregistrer" :loading="saving" @click="save" />
      </div>
      <div class="text-caption text-grey-7 q-mt-xs">
        Un membre d'un département reçoit ses <b>courriels</b> ET ses <b>tickets</b> (et les canaux à venir) — une seule inscription, tous les canaux.
        Cochez les départements de chaque personne.
      </div>

      <div class="row q-gutter-xs q-mt-sm">
        <q-chip v-for="q in queues" :key="q" dense square color="grey-2" text-color="grey-8">
          {{ queueLabel(q) }} · <b class="q-ml-xs">{{ queueCount(q) }}</b>
        </q-chip>
      </div>

      <q-input dense outlined v-model="search" placeholder="Chercher une personne…" clearable class="q-mt-sm">
        <template #prepend><q-icon name="search" /></template>
      </q-input>

      <div v-if="loading" class="text-grey-6 q-pa-md text-center"><q-spinner size="20px" /> Chargement…</div>
      <div v-else class="dept-list q-mt-sm">
        <div v-for="a in filtered" :key="a.email" class="dept-row">
          <div class="dept-who">
            <q-avatar size="26px" color="green-1" text-color="green-8" style="font-size:11px;font-weight:600">{{ ini(a.name) }}</q-avatar>
            <div class="dept-who-txt">
              <b class="ellipsis">{{ a.name }}</b>
              <div class="text-caption text-grey-6 ellipsis">{{ a.email }}</div>
            </div>
          </div>
          <div class="dept-ctrl">
            <div class="dept-chips">
              <q-chip v-for="q in queues" :key="q" clickable dense
                :color="isMember(a.email, q) ? 'primary' : 'grey-3'"
                :text-color="isMember(a.email, q) ? 'white' : 'grey-7'"
                @click="toggle(a.email, q)">{{ queueLabel(q) }}</q-chip>
            </div>
            <div class="dept-mode">
              <q-btn-toggle :model-value="modeOf(a.email)" @update:model-value="m => setMode(a.email, m)"
                dense unelevated no-caps size="sm" toggle-color="primary" color="grey-2" text-color="grey-8"
                :options="MODES.map(x => ({ label: x.label, value: x.value, icon: x.icon }))" />
              <q-select v-if="modeOf(a.email) === 'tags'" :model-value="tagsOf(a.email)" @update:model-value="t => setTags(a.email, t)"
                dense outlined multiple use-chips use-input new-value-mode="add-unique"
                :options="skillOptions" placeholder="compétences…" class="dept-tagsel" />
            </div>
          </div>
        </div>
        <div v-if="!filtered.length" class="text-grey-6 q-pa-md text-center">Aucune personne.</div>
      </div>
    </q-card-section>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { Notify } from 'quasar'
import { HUB_URL } from 'src/config/hub'
import { staffInitials } from 'src/composables/useFormatters'
import { fetchTags } from 'src/api/dispatch' // compétences PARTAGÉES (Dispatch Tag, catégorie « Compétence ») — taxonomie unique réutilisée du dispatch

const agents = ref([])      // [{ email, name }]
const queues = ref([])      // les 4 files = départements omnichannel (categories.js QUEUES)
const labels = ref({})
const membersMap = reactive({}) // { queue: [emails lowercase] } — édité localement, sauvé en bloc
const visibility = reactive({}) // { email: { mode:'personnel'|'department'|'tags', tags:[...] } } — réduction du bruit par personne
const MODES = [
  { value: 'personnel', label: 'Perso', icon: 'person', hint: 'Seulement assignés / assistant / suivis — aucun bruit de département' },
  { value: 'department', label: 'Département', icon: 'groups', hint: 'Tous les tickets de ses files' },
  { value: 'tags', label: 'Dépt + compétences', icon: 'sell', hint: 'Ses files, filtrées à ses COMPÉTENCES (taxonomie partagée avec le dispatch)' },
]
const TAG_SUGGESTIONS = ['téléphonie', 'installation', 'fibre', 'television', 'internet', 'dépannage', 'reseau'] // repli si aucune compétence définie côté dispatch
const skillOptions = ref([]) // compétences PARTAGÉES (Dispatch Tag catégorie « Compétence ») — alimente le sélecteur ; saisie libre permise en plus
const search = ref('')
const loading = ref(false)
const saving = ref(false)
const dirty = ref(false)

const ini = (n) => staffInitials(n || '?')
const queueLabel = (q) => labels.value[q] || q
const queueCount = (q) => (membersMap[q] || []).length
const isMember = (email, q) => (membersMap[q] || []).includes(String(email).toLowerCase())
const modeOf = (email) => (visibility[String(email).toLowerCase()] || {}).mode || 'department'
function setMode (email, m) { const e = String(email).toLowerCase(); if (!visibility[e]) visibility[e] = { mode: 'department', tags: [] }; visibility[e].mode = m; dirty.value = true }
const tagsOf = (email) => (visibility[String(email).toLowerCase()] || {}).tags || []
function setTags (email, tags) { const e = String(email).toLowerCase(); if (!visibility[e]) visibility[e] = { mode: 'tags', tags: [] }; visibility[e].tags = (tags || []).map(t => String(t).trim().toLowerCase()).filter(Boolean); dirty.value = true }

const filtered = computed(() => {
  const s = search.value.trim().toLowerCase()
  if (!s) return agents.value
  return agents.value.filter(a => a.email.includes(s) || (a.name || '').toLowerCase().includes(s))
})

function toggle (email, q) {
  const e = String(email).toLowerCase()
  if (!membersMap[q]) membersMap[q] = []
  const i = membersMap[q].indexOf(e)
  if (i >= 0) membersMap[q].splice(i, 1)
  else membersMap[q].push(e)
  dirty.value = true
}

async function load () {
  loading.value = true
  try {
    const [aR, mR] = await Promise.all([
      fetch(`${HUB_URL}/conversations/agents`).then(r => r.json()),
      fetch(`${HUB_URL}/conversations/queue-members`).then(r => r.json()),
    ])
    const names = aR.names || {}
    agents.value = (aR.agents || []).map(e => ({ email: e, name: names[e] || e }))
    queues.value = mR.queues || []
    labels.value = mR.labels || {}
    const m = mR.members || {}
    for (const q of queues.value) membersMap[q] = (m[q] || []).map(e => String(e).toLowerCase())
    const vis = mR.visibility || {}
    for (const k of Object.keys(vis)) visibility[String(k).toLowerCase()] = { mode: vis[k].mode || 'department', tags: Array.isArray(vis[k].tags) ? vis[k].tags : [] }
    dirty.value = false
  } catch (e) { Notify.create({ type: 'negative', message: 'Chargement des départements échoué' }) }
  loading.value = false
}

async function save () {
  saving.value = true
  try {
    const members = {}
    for (const q of queues.value) members[q] = membersMap[q] || []
    const r = await fetch(`${HUB_URL}/conversations/queue-members`, {
      method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ members, visibility: { ...visibility } }),
    })
    if (r.ok) { dirty.value = false; Notify.create({ type: 'positive', message: 'Abonnements enregistrés' }) }
    else Notify.create({ type: 'negative', message: 'Échec de l\'enregistrement' })
  } catch (e) { Notify.create({ type: 'negative', message: e.message }) }
  saving.value = false
}

async function loadSkills () {
  try {
    const tags = await fetchTags()
    const skills = (tags || []).filter(t => /comp[ée]tence|skill/i.test(t.category || '')).map(t => t.label || t.name).filter(Boolean)
    skillOptions.value = skills.length ? [...new Set(skills)].sort() : TAG_SUGGESTIONS
  } catch { skillOptions.value = TAG_SUGGESTIONS }
}

onMounted(() => { load(); loadSkills() })
</script>

<style scoped>
.dept-list { max-height: 52vh; overflow-y: auto; border: 1px solid #eef2f7; border-radius: 8px; }
.dept-row { display: flex; align-items: flex-start; gap: 10px; padding: 8px 10px; border-bottom: 1px solid #f1f5f9; }
.dept-row:last-child { border-bottom: 0; }
.dept-who { display: flex; align-items: center; gap: 8px; min-width: 180px; max-width: 230px; flex: 0 0 auto; padding-top: 3px; }
.dept-who-txt { min-width: 0; }
.dept-ctrl { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; align-items: flex-end; }
.dept-chips { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }
.dept-mode { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: flex-end; }
.dept-tagsel { min-width: 200px; max-width: 320px; }
@media (max-width: 700px) { .dept-row { flex-direction: column; align-items: stretch; } .dept-who { max-width: none; } .dept-ctrl { align-items: stretch; } .dept-chips, .dept-mode { justify-content: flex-start; } }
</style>
