<template>
  <q-page padding>
    <div class="text-h5 q-mb-md">
      <q-icon name="settings" class="q-mr-sm" /> Parametres
    </div>

    <div v-if="loading" class="flex flex-center q-pa-xl">
      <q-spinner size="40px" color="primary" />
    </div>

    <template v-else>

      <!-- SECTION 1: Utilisateurs & Permissions -->
      <div v-if="can('manage_permissions')" class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7">
          <template #header>
            <SectionHeader icon="admin_panel_settings" label="Utilisateurs & Permissions" />
          </template>

          <q-separator />
          <div class="q-pa-md">

            <q-tabs v-model="permTab" dense no-caps active-color="primary" indicator-color="primary"
              class="q-mb-md text-grey-7" align="left">
              <q-tab name="users" icon="people" label="Utilisateurs" />
              <q-tab name="groups" icon="groups" label="Groupes" />
              <q-tab name="matrix" icon="grid_on" label="Matrice" />
              <q-tab name="identities" icon="badge" label="Identités" />
              <q-tab name="staff" icon="manage_accounts" label="Staff" />
            </q-tabs>

            <!-- TAB: Identités unifiées (label + alias courriel + lien tech + fusion) -->
            <div v-show="permTab === 'identities'">
              <IdentityManager />
            </div>

            <!-- TAB: Console Staff (réconciliation Authentik ↔ System User/Employee/Tech ; provisionner/désactiver/supprimer) -->
            <div v-show="permTab === 'staff'">
              <StaffConsole />
            </div>

            <!-- TAB: Utilisateurs -->
            <div v-show="permTab === 'users'">
              <div class="row q-gutter-sm items-end q-mb-md">
                <q-input v-model="userSearch" label="Rechercher un utilisateur (nom, email)..." outlined dense
                  style="min-width:300px;flex:1" @update:model-value="debouncedSearchUsers" debounce="350"
                  autocomplete="off" name="user-search-nope">
                  <template #append>
                    <q-spinner v-if="userSearchLoading" size="16px" color="primary" />
                    <q-icon v-else-if="userSearch" name="close" class="cursor-pointer" @click="userSearch = ''; userResults = []; selectedUser = null" />
                  </template>
                </q-input>
                <q-btn v-if="can('manage_users')" unelevated color="primary" icon="person_add" label="Inviter"
                  @click="openInviteDialog()" no-caps />
              </div>

              <!-- Invite dialog — POST /auth/users on the hub creates the
                   user in BOTH Authentik (with recovery email) and ERPNext
                   in one round-trip. Defaults to sysadmin group + Employee
                   role; admin can adjust before sending. -->
              <q-dialog v-model="inviteOpen" persistent>
                <q-card style="min-width:420px;max-width:520px">
                  <q-card-section class="row items-center q-pb-none">
                    <div class="text-h6">Inviter un utilisateur</div>
                    <q-space />
                    <q-btn flat round dense icon="close" v-close-popup :disable="inviteSaving" />
                  </q-card-section>

                  <!-- Form (hidden after success — we replace it with the credentials panel) -->
                  <q-card-section v-if="!lastInviteResult" class="q-pt-sm">
                    <div class="text-caption text-grey-7 q-mb-md">
                      Un mot de passe temporaire sera généré, envoyé par courriel,
                      et affiché ici en cas de problème de livraison.
                      L'utilisateur pourra le changer après sa première connexion.
                    </div>
                    <q-input v-model="inviteForm.full_name" label="Nom complet *" outlined dense class="q-mb-sm"
                      autofocus :disable="inviteSaving" />
                    <q-input v-model="inviteForm.email" label="Email *" type="email" outlined dense class="q-mb-md"
                      placeholder="prenom@targointernet.com" :disable="inviteSaving" />

                    <div class="text-subtitle2 q-mb-xs">Groupes Authentik</div>
                    <div class="row q-gutter-sm q-mb-md">
                      <q-chip v-for="g in ['admin','sysadmin','tech','support','comptabilite','facturation','dev']"
                        :key="g" clickable
                        :color="inviteForm.groups.includes(g) ? 'primary' : 'grey-3'"
                        :text-color="inviteForm.groups.includes(g) ? 'white' : 'grey-7'"
                        :icon="inviteForm.groups.includes(g) ? 'check' : 'add'"
                        @click="inviteForm.groups.includes(g)
                          ? inviteForm.groups.splice(inviteForm.groups.indexOf(g), 1)
                          : inviteForm.groups.push(g)"
                        size="sm">
                        {{ g }}
                      </q-chip>
                    </div>

                    <div class="text-subtitle2 q-mb-xs">Rôles ERPNext</div>
                    <q-input v-model="inviteForm.rolesText" outlined dense placeholder="Employee, Sales User, …"
                      hint="Séparés par des virgules"
                      @update:model-value="v => inviteForm.roles = v.split(',').map(r => r.trim()).filter(Boolean)" />
                  </q-card-section>

                  <!-- Success panel — shown once the user has been created.
                       Big takeaway: the recovery URL the admin must forward. -->
                  <q-card-section v-else class="q-pt-sm">
                    <div class="row items-center q-mb-md">
                      <q-icon name="check_circle" color="green-7" size="32px" class="q-mr-sm" />
                      <div>
                        <div class="text-weight-bold">{{ lastInviteResult.full_name }} ajouté</div>
                        <div class="text-caption text-grey-7">{{ lastInviteResult.email }}</div>
                      </div>
                    </div>

                    <!-- Credentials panel: shows the temp password + delivery status. -->
                    <div v-if="lastInviteResult.temp_password" class="q-pa-sm q-mb-sm"
                      :style="lastInviteResult.email_sent
                        ? 'background:#ecfdf5;border-left:3px solid #10b981;border-radius:6px'
                        : 'background:#fef3c7;border-left:3px solid #d97706;border-radius:6px'">
                      <div class="text-caption text-weight-bold q-mb-xs">
                        <span v-if="lastInviteResult.email_sent">✓ Courriel envoyé à {{ lastInviteResult.email }}</span>
                        <span v-else>⚠️ Courriel non envoyé — transmettez le mot de passe manuellement</span>
                      </div>
                      <div class="text-caption text-grey-8 q-mb-sm">
                        Mot de passe temporaire (à changer à la première connexion) :
                      </div>
                      <q-input :model-value="lastInviteResult.temp_password" readonly outlined dense class="q-mb-sm"
                        input-class="text-mono">
                        <template #append>
                          <q-btn flat dense round icon="content_copy" color="primary" @click="copyTempPassword">
                            <q-tooltip>Copier</q-tooltip>
                          </q-btn>
                        </template>
                      </q-input>
                    </div>
                    <div v-else class="text-caption text-negative q-mb-sm">
                      ✗ Mot de passe non défini — vérifier les logs du hub
                    </div>

                    <div v-if="lastInviteResult.erpnext_ok" class="text-caption text-grey-7">
                      ✓ Compte ERPNext System User créé
                    </div>
                    <div v-else class="text-caption text-negative">
                      ✗ ERPNext: {{ lastInviteResult.erpnext_error }}
                    </div>
                  </q-card-section>

                  <q-card-actions align="right" class="q-pb-md q-pr-md">
                    <template v-if="!lastInviteResult">
                      <q-btn flat label="Annuler" v-close-popup :disable="inviteSaving" />
                      <q-btn unelevated color="primary" label="Créer l'utilisateur" icon="person_add"
                        :loading="inviteSaving" @click="submitInvite()" />
                    </template>
                    <template v-else>
                      <q-btn flat label="Inviter un autre" @click="lastInviteResult = null; openInviteDialog()" />
                      <q-btn unelevated color="primary" label="Terminé" v-close-popup />
                    </template>
                  </q-card-actions>
                </q-card>
              </q-dialog>

              <div v-if="userResults.length" class="user-list">
                <div v-for="u in userResults" :key="u.pk" class="user-card"
                  :class="{ 'user-card--selected': selectedUser?.pk === u.pk }"
                  @click="selectUser(u)">
                  <div class="row items-center no-wrap">
                    <UserAvatar :email="u.email" :name="u.name || u.username" :size="36" class="q-mr-sm" />

                    <div class="col">
                      <div class="text-weight-bold text-body2">{{ u.name || u.username }}</div>
                      <div class="text-caption text-grey-6">{{ u.email }}</div>
                    </div>
                    <q-badge v-if="!u.is_active" label="inactif" color="red-1" text-color="red-9" class="q-mr-xs" />
                    <q-badge v-if="u.is_superuser" label="superuser" color="amber-1" text-color="amber-9" class="q-mr-xs" />
                    <div class="row q-gutter-xs">
                      <q-badge v-for="g in u.groups" :key="g" :label="g" color="green-1" text-color="green-8"
                        class="text-caption" style="font-size:0.7rem" />
                    </div>
                    <q-icon name="chevron_right" color="grey-5" class="q-ml-sm" />
                  </div>
                </div>
              </div>
              <div v-else-if="userSearchDone" class="text-center text-grey-5 q-py-lg">
                Aucun utilisateur trouve
              </div>

              <!-- Selected user detail panel -->
              <q-slide-transition>
                <div v-if="selectedUser" class="user-detail-panel q-mt-md">
                  <input ref="teamAvatarInput" type="file" accept="image/png,image/jpeg,image/webp,image/gif"
                    class="hidden" @change="onTeamAvatarFile">
                  <div class="row items-center q-mb-md">
                    <!-- Avatar éditable par un admin (upload pour ce membre via ?as=). -->
                    <div class="ua-edit q-mr-md" :class="{ 'ua-edit--can': can('manage_users') }"
                      @click="can('manage_users') && pickTeamAvatar(selectedUser)">
                      <UserAvatar :email="selectedUser.email" :name="selectedUser.name || selectedUser.username" :size="42" />
                      <div v-if="can('manage_users')" class="ua-edit__cam">
                        <q-icon name="photo_camera" size="12px" color="white" />
                      </div>
                      <q-tooltip v-if="can('manage_users')">Changer la photo</q-tooltip>
                    </div>
                    <div class="col">
                      <!-- Nom complet éditable (source Authentik, affichée partout). -->
                      <div v-if="!editingName" class="row items-center no-wrap">
                        <div class="text-h6">{{ selectedUser.name || selectedUser.username }}</div>
                        <q-btn v-if="can('manage_users')" flat round dense size="sm" icon="edit"
                          color="grey-6" class="q-ml-xs" @click="startEditName(selectedUser)">
                          <q-tooltip>Modifier le nom complet</q-tooltip>
                        </q-btn>
                      </div>
                      <div v-else class="row items-center no-wrap q-gutter-xs" style="max-width:420px">
                        <q-input v-model="nameDraft" dense outlined autofocus class="col"
                          :disable="savingName" @keyup.enter="commitEditName(selectedUser)"
                          @keyup.esc="editingName = false" />
                        <q-btn round dense unelevated color="primary" icon="check" :loading="savingName"
                          @click="commitEditName(selectedUser)" />
                        <q-btn round dense flat icon="close" :disable="savingName" @click="editingName = false" />
                      </div>
                      <div class="text-caption text-grey-6">{{ selectedUser.email }}</div>
                      <div v-if="selectedUser.last_login" class="text-caption text-grey-5">
                        Derniere connexion: {{ formatDate(selectedUser.last_login) }}
                      </div>
                    </div>
                    <q-btn flat round dense icon="close" @click="selectedUser = null; editingName = false" />
                  </div>

                  <!-- Profil employé lié (ERPNext) — lien session ↔ Employee -->
                  <div class="q-mb-md emp-card">
                    <div class="row items-center q-mb-xs">
                      <div class="text-subtitle2"><q-icon name="badge" size="18px" class="q-mr-xs" />Profil employé</div>
                      <q-space />
                      <q-spinner v-if="empResolving" size="16px" color="primary" />
                    </div>
                    <template v-if="!empResolving">
                      <div v-if="selectedEmployee" class="row items-center no-wrap">
                        <div class="col">
                          <div class="text-body2 text-weight-medium">{{ selectedEmployee.employee_name }}</div>
                          <div class="text-caption text-grey-6">
                            {{ [selectedEmployee.designation, selectedEmployee.department].filter(Boolean).join(' · ') || '—' }}
                            <span v-if="selectedEmployee.cell_number"> · {{ selectedEmployee.cell_number }}</span>
                          </div>
                        </div>
                        <q-btn dense flat no-caps color="primary" icon="edit" label="Modifier"
                          @click="openEmpEdit(selectedEmployee.name)" />
                      </div>
                      <div v-else class="row items-center no-wrap">
                        <div class="col text-caption text-grey-6"><q-icon name="link_off" size="14px" /> Aucun profil employé lié à ce compte.</div>
                        <q-btn dense unelevated no-caps color="primary" icon="link" label="Lier un employé"
                          @click="openEmpLink(selectedUser.email)" />
                      </div>
                    </template>
                  </div>

                  <!-- Groups assignment -->
                  <div class="q-mb-md">
                    <div class="text-subtitle2 q-mb-xs">
                      <q-icon name="groups" size="18px" class="q-mr-xs" />Groupes
                    </div>
                    <div class="row q-gutter-sm items-center flex-wrap">
                      <q-chip v-for="g in allGroupNames" :key="g" clickable
                        :color="selectedUser.groups.includes(g) ? 'primary' : 'grey-3'"
                        :text-color="selectedUser.groups.includes(g) ? 'white' : 'grey-7'"
                        :icon="selectedUser.groups.includes(g) ? 'check_circle' : 'radio_button_unchecked'"
                        size="md" @click="toggleUserGroup(selectedUser, g)">
                        {{ g }}
                      </q-chip>
                    </div>
                    <div v-if="savingGroups" class="text-caption text-grey-5 q-mt-xs">
                      <q-spinner size="12px" class="q-mr-xs" /> Sauvegarde...
                    </div>
                  </div>

                  <!-- Permission overrides -->
                  <q-expansion-item dense label="Overrides individuels" caption="Forcer ON/OFF par capacite"
                    icon="tune" header-class="text-grey-7" class="q-mb-sm"
                    :default-opened="Object.keys(selectedUser.overrides).length > 0">
                    <div class="q-pa-sm">
                      <PermGrid :categories="permCategories" :caps-by-category="permCapsByCategory">
                        <template #cap="{ cap }">
                          <div class="perm-override-chip"
                            :class="{
                              'perm-override-on': selectedUser.overrides[cap.key] === true,
                              'perm-override-off': selectedUser.overrides[cap.key] === false
                            }">
                            <q-checkbox v-model="selectedUser.overrides[cap.key]" dense size="sm" color="warning"
                              indeterminate-value="undefined" toggle-indeterminate
                              @update:model-value="v => setUserOverride(selectedUser, cap.key, v)" />
                            <span class="text-caption">{{ cap.label }}</span>
                          </div>
                        </template>
                      </PermGrid>
                      <div class="text-caption text-grey-5 q-mt-xs">
                        Indetermine = herite du groupe. Coche = force ON. Decoche = force OFF.
                      </div>
                    </div>
                  </q-expansion-item>

                  <!-- Effective permissions summary -->
                  <q-expansion-item dense label="Permissions effectives" caption="Resultat final (groupes + overrides)"
                    icon="verified_user" header-class="text-grey-7">
                    <div class="q-pa-sm">
                      <div class="effective-perms">
                        <template v-for="cat in permCategories" :key="cat">
                          <div class="override-cat-label">{{ cat }}</div>
                          <div class="row q-gutter-xs flex-wrap q-mb-xs">
                            <q-badge v-for="cap in permCapsByCategory[cat]" :key="cap.key"
                              :color="effectivePerm(selectedUser, cap.key) ? 'green-1' : 'grey-2'"
                              :text-color="effectivePerm(selectedUser, cap.key) ? 'green-9' : 'grey-5'"
                              class="q-pa-xs" style="font-size:0.72rem">
                              <q-icon :name="effectivePerm(selectedUser, cap.key) ? 'check' : 'close'" size="12px" class="q-mr-xs" />
                              {{ cap.label }}
                            </q-badge>
                          </div>
                        </template>
                      </div>
                    </div>
                  </q-expansion-item>
                </div>
              </q-slide-transition>

              <EmployeeEditDialog v-model="empDlgOpen" :employee-name="empDlgName" :link-email="empDlgLinkEmail"
                @saved="onEmployeeSaved" />
            </div>

            <!-- TAB: Groupes -->
            <div v-show="permTab === 'groups'">
              <!-- Legacy sync banner -->
              <div class="row items-center q-mb-md q-pa-sm" style="background:#fef3c7;border-radius:8px;border:1px solid #fde68a">
                <q-icon name="sync" size="20px" color="warning" class="q-mr-sm" />
                <span class="text-body2 text-warning">Importer les groupes depuis le systeme legacy</span>
                <q-space />
                <q-btn dense unelevated color="warning" text-color="white" icon="preview" label="Apercu"
                  :loading="legacySyncing" @click="syncLegacy(true)" class="q-mr-xs" size="sm" />
                <q-btn dense unelevated color="primary" icon="sync" label="Synchroniser"
                  :loading="legacySyncing" @click="syncLegacy(false)" size="sm" />
              </div>

              <!-- Sync results dialog -->
              <q-dialog v-model="showSyncDialog" position="right" full-height>
                <q-card style="width:550px;max-width:90vw" class="column no-wrap">
                  <q-card-section class="row items-center q-pb-sm" style="border-bottom:1px solid #e2e8f0">
                    <q-icon :name="syncResult?.dry_run ? 'preview' : 'check_circle'" size="22px"
                      :color="syncResult?.dry_run ? 'amber-8' : 'green-7'" class="q-mr-sm" />
                    <div class="text-subtitle1 text-weight-bold">
                      {{ syncResult?.dry_run ? 'Apercu sync legacy' : 'Sync terminee' }}
                    </div>
                    <q-space />
                    <q-btn flat round dense icon="close" @click="showSyncDialog = false" />
                  </q-card-section>

                  <q-card-section v-if="syncResult" class="col" style="overflow-y:auto">
                    <div class="row q-gutter-sm q-mb-md">
                      <q-badge color="green-1" text-color="green-8" class="q-pa-sm">
                        <q-icon name="add_circle" size="14px" class="q-mr-xs" />
                        {{ syncResult.summary.to_sync }} a synchroniser
                      </q-badge>
                      <q-badge color="green-1" text-color="green-8" class="q-pa-sm">
                        <q-icon name="check" size="14px" class="q-mr-xs" />
                        {{ syncResult.summary.already_ok }} deja OK
                      </q-badge>
                      <q-badge color="amber-1" text-color="amber-9" class="q-pa-sm">
                        <q-icon name="help" size="14px" class="q-mr-xs" />
                        {{ syncResult.summary.not_found }} non trouves
                      </q-badge>
                      <q-badge v-if="syncResult.summary.errors" color="red-1" text-color="red-9" class="q-pa-sm">
                        <q-icon name="error" size="14px" class="q-mr-xs" />
                        {{ syncResult.summary.errors }} erreurs
                      </q-badge>
                    </div>

                    <div v-if="syncResult.matched.length" class="q-mb-md">
                      <div class="text-subtitle2 q-mb-xs">
                        {{ syncResult.dry_run ? 'Utilisateurs a ajouter' : 'Utilisateurs synchronises' }}
                      </div>
                      <div v-for="m in syncResult.matched" :key="m.email" class="row items-center q-py-xs"
                        style="border-bottom:1px solid #f1f5f9;font-size:0.85rem">
                        <q-icon :name="m.status === 'synced' ? 'check_circle' : 'schedule'" size="16px"
                          :color="m.status === 'synced' ? 'green-6' : 'amber-6'" class="q-mr-sm" />
                        <span class="text-weight-medium">{{ m.username }}</span>
                        <span class="text-grey-6 q-ml-sm">{{ m.email }}</span>
                        <q-space />
                        <q-badge :label="m.group" color="green-1" text-color="green-8" />
                      </div>
                    </div>

                    <div v-if="syncResult.not_found.length" class="q-mb-md">
                      <div class="text-subtitle2 q-mb-xs text-warning">Non trouves dans Authentik</div>
                      <div v-for="m in syncResult.not_found" :key="m.email" class="row items-center q-py-xs"
                        style="border-bottom:1px solid #f1f5f9;font-size:0.85rem">
                        <q-icon name="person_off" size="16px" color="warning" class="q-mr-sm" />
                        <span>{{ m.name }}</span>
                        <span class="text-grey-6 q-ml-sm">{{ m.email }}</span>
                        <q-space />
                        <q-badge :label="m.legacy_group" color="grey-3" text-color="grey-7" />
                      </div>
                    </div>

                    <q-expansion-item v-if="syncResult.already_ok.length" dense
                      :label="`${syncResult.already_ok.length} deja dans le bon groupe`"
                      icon="check_circle" header-class="text-green-7 text-caption">
                      <div class="q-pa-xs">
                        <div v-for="m in syncResult.already_ok" :key="m.email" class="text-caption text-grey-6 q-py-xs">
                          {{ m.email }} → {{ m.group }}
                        </div>
                      </div>
                    </q-expansion-item>

                    <div v-if="syncResult.dry_run && syncResult.summary.to_sync > 0" class="q-mt-md text-center">
                      <q-btn color="primary" icon="sync" label="Appliquer la synchronisation"
                        unelevated :loading="legacySyncing" @click="showSyncDialog = false; syncLegacy(false)" />
                    </div>
                  </q-card-section>
                </q-card>
              </q-dialog>

              <div v-if="permLoading" class="flex flex-center q-pa-md"><q-spinner size="28px" color="primary" /></div>
              <div v-else class="group-cards">
                <div v-for="g in permGroups" :key="g.name" class="group-card"
                  :class="{ 'group-card--selected': selectedGroup === g.name }"
                  @click="selectGroup(g.name)">
                  <div class="row items-center no-wrap q-mb-sm">
                    <q-icon name="groups" size="20px" color="primary" class="q-mr-sm" />
                    <span class="text-weight-bold">{{ g.name }}</span>
                    <q-space />
                    <q-badge :label="g.num_users + ' membres'" color="green-1" text-color="green-8" />
                  </div>
                  <div class="text-caption text-grey-6">
                    {{ countGroupPerms(g) }} permissions actives
                  </div>
                </div>
              </div>

              <!-- Group detail -->
              <q-slide-transition>
                <div v-if="selectedGroup && groupMembers" class="q-mt-md group-detail-panel">
                  <div class="row items-center q-mb-md">
                    <q-icon name="groups" size="24px" color="primary" class="q-mr-sm" />
                    <span class="text-h6">{{ selectedGroup }}</span>
                    <q-space />
                    <q-btn flat round dense icon="close" @click="selectedGroup = null; groupMembers = null" />
                  </div>

                  <div class="text-subtitle2 q-mb-xs">Membres</div>
                  <div v-if="groupMembersLoading" class="text-caption text-grey-5">
                    <q-spinner size="14px" class="q-mr-xs" /> Chargement...
                  </div>
                  <div v-else>
                    <div v-for="m in groupMembers" :key="m.pk" class="row items-center q-py-xs q-px-sm member-row">
                      <UserAvatar :email="m.email" :name="m.name || m.username" :size="28" class="q-mr-sm" />
                      <span class="text-body2">{{ m.name || m.username }}</span>
                      <span class="text-caption text-grey-6 q-ml-sm">{{ m.email }}</span>
                      <q-space />
                      <q-btn flat round dense icon="person_remove" size="sm" color="negative" class="member-row-del"
                        @click="removeFromGroup(m, selectedGroup)" title="Retirer du groupe">
                        <q-tooltip>Retirer du groupe</q-tooltip>
                      </q-btn>
                    </div>
                    <div v-if="groupMembers.length === 0" class="text-caption text-grey-5 q-py-sm">
                      Aucun membre dans ce groupe
                    </div>
                  </div>

                  <!-- Add member -->
                  <div class="q-mt-sm" style="position:relative">
                    <q-input v-model="addMemberSearch" label="Ajouter un membre..." outlined dense
                      autocomplete="off" name="add-member-nope"
                      @update:model-value="debouncedMemberSearch">
                      <template #append>
                        <q-spinner v-if="memberSearchLoading" size="16px" color="primary" />
                        <q-icon v-else-if="addMemberSearch" name="close" class="cursor-pointer"
                          @click="addMemberSearch = ''; memberSearchResults = []" />
                      </template>
                    </q-input>
                    <div v-if="memberSearchResults.length" class="member-search-dropdown">
                      <div v-for="u in memberSearchResults" :key="u.pk" class="member-search-item"
                        @click="addUserToCurrentGroup(u)">
                        <UserAvatar :email="u.email" :name="u.name || u.username" :size="24" class="q-mr-sm" />
                        <span class="text-body2">{{ u.name || u.username }}</span>
                        <span class="text-caption text-grey-6 q-ml-sm">{{ u.email }}</span>
                        <q-badge v-if="u.groups.includes(selectedGroup)" label="deja membre" color="grey-3" text-color="grey-6" class="q-ml-auto" />
                      </div>
                    </div>
                  </div>

                  <!-- Group permissions inline -->
                  <q-expansion-item dense label="Permissions du groupe" icon="security"
                    header-class="text-grey-7 q-mt-md" default-opened>
                    <div class="q-pa-sm">
                      <PermGrid :categories="permCategories" :caps-by-category="permCapsByCategory">
                        <template #cap="{ cap }">
                          <div class="perm-override-chip"
                            :class="{ 'perm-override-on': permMatrix[selectedGroup]?.[cap.key] }">
                            <q-checkbox v-model="permMatrix[selectedGroup][cap.key]" dense size="sm" color="primary"
                              @update:model-value="permDirty = true" />
                            <span class="text-caption">{{ cap.label }}</span>
                          </div>
                        </template>
                      </PermGrid>
                      <q-btn v-if="permDirty" color="primary" icon="save" label="Sauvegarder permissions"
                        dense unelevated :loading="permSaving" @click="saveGroupPerms(selectedGroup)" class="q-mt-sm" />
                    </div>
                  </q-expansion-item>
                </div>
              </q-slide-transition>
            </div>

            <!-- TAB: Matrice (vue globale) -->
            <div v-show="permTab === 'matrix'">
              <div class="row items-center q-mb-sm">
                <span class="text-subtitle2">Matrice globale Groupes x Capacites</span>
                <q-space />
                <q-btn v-if="permDirty" color="primary" icon="save" label="Sauvegarder" dense unelevated
                  :loading="permSaving" @click="saveAllPerms" />
              </div>
              <div v-if="permLoading" class="flex flex-center q-pa-md"><q-spinner size="28px" color="primary" /></div>
              <div v-else-if="permGroups.length" class="perm-matrix">
                <table class="perm-table">
                  <thead>
                    <tr>
                      <th class="perm-cap-col">Capacite</th>
                      <th v-for="g in permGroups" :key="g.name" class="perm-group-col">
                        {{ g.name }}
                        <div class="text-caption text-grey-6">{{ g.num_users }}</div>
                      </th>
                    </tr>
                  </thead>
                  <tbody>
                    <template v-for="cat in permCategories" :key="cat">
                      <tr class="perm-cat-row">
                        <td :colspan="permGroups.length + 1" class="text-weight-bold text-grey-7">{{ cat }}</td>
                      </tr>
                      <tr v-for="cap in permCapsByCategory[cat]" :key="cap.key">
                        <td class="perm-cap-label">{{ cap.label }}</td>
                        <td v-for="g in permGroups" :key="g.name" class="text-center">
                          <q-checkbox v-model="permMatrix[g.name][cap.key]" dense size="sm" color="primary"
                            @update:model-value="permDirty = true" />
                        </td>
                      </tr>
                    </template>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 2: SMS / Twilio -->
      <div class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7">
          <template #header>
            <SectionHeader icon="sms" label="SMS & Templates" />
          </template>
          <q-separator />
          <div class="q-pa-md">
            <div class="row q-col-gutter-md">
              <div class="col-12 col-md-6">
                <q-input v-model="settings.twilio_account_sid" label="Account SID" outlined dense
                  placeholder="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                  @blur="save('twilio_account_sid')" />
              </div>
              <div class="col-12 col-md-6">
                <q-input v-model="settings.twilio_auth_token" label="Auth Token" outlined dense
                  :type="showToken ? 'text' : 'password'" placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                  @blur="save('twilio_auth_token')">
                  <template #append>
                    <q-icon :name="showToken ? 'visibility_off' : 'visibility'" class="cursor-pointer"
                      @click="showToken = !showToken" />
                  </template>
                </q-input>
              </div>
              <div class="col-12 col-md-6">
                <q-input v-model="settings.twilio_from_number" label="Numero d'envoi (From)" outlined dense
                  placeholder="+15145551234"
                  @blur="save('twilio_from_number')" />
              </div>
              <div class="col-12 col-md-6">
                <div class="row items-center q-gutter-sm">
                  <q-btn color="primary" icon="send" label="Tester SMS" :loading="testingSms" dense unelevated
                    @click="testSms" :disable="!settings.twilio_account_sid || !settings.twilio_from_number" />
                  <q-badge v-if="smsTestResult" :color="smsTestResult.ok ? 'green' : 'red'" class="q-pa-xs">
                    {{ smsTestResult.message }}
                  </q-badge>
                </div>
              </div>
            </div>
            <div class="text-caption text-grey-6 q-mt-sm">
              Les credentials Twilio permettent l'envoi de SMS depuis la fiche client.
              <a href="https://console.twilio.com" target="_blank">Console Twilio</a>
            </div>

            <q-separator class="q-my-md" />
            <div class="text-subtitle2 q-mb-sm">Templates SMS</div>
            <div class="row q-col-gutter-md">
              <div v-for="t in smsTemplates" :key="t.key" class="col-12">
                <q-input v-model="settings[t.key]" :label="t.label" outlined dense autogrow
                  @blur="save(t.key)" />
              </div>
            </div>
            <div class="text-caption text-grey-6 q-mt-sm">
              Variables: <code>{client_name}</code>, <code>{tech_name}</code>, <code>{eta}</code>, <code>{job_id}</code>, <code>{address}</code>, <code>{duration}</code>
            </div>
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 3: Integrations -->
      <div class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7">
          <template #header>
            <SectionHeader icon="extension" label="Integrations" />
          </template>
          <q-separator />
          <div class="q-pa-md">

            <div class="text-subtitle2 q-mb-xs">
              <q-icon name="email" size="18px" class="q-mr-xs" /> Email — SMTP
            </div>
            <div class="text-caption text-grey-6 q-mb-md">
              La configuration SMTP (Mailjet) se fait dans ERPNext.
              <a v-if="can('manage_settings')" :href="erpDeskUrl + '/app/email-account'" target="_blank">Configurer</a>
            </div>

            <q-separator class="q-my-md" />

            <div class="text-subtitle2 q-mb-xs">
              <q-icon name="webhook" size="18px" class="q-mr-xs" /> n8n — Webhooks
            </div>
            <div class="row q-col-gutter-md q-mb-md">
              <div class="col-12 col-md-6">
                <q-input v-model="settings.n8n_url" label="n8n URL" outlined dense @blur="save('n8n_url')" />
              </div>
              <div class="col-12 col-md-6">
                <q-input v-model="settings.n8n_webhook_base" label="Webhook base URL" outlined dense @blur="save('n8n_webhook_base')" />
              </div>
            </div>

            <q-separator class="q-my-md" />

            <div class="text-subtitle2 q-mb-xs">
              <q-icon name="credit_card" size="18px" class="q-mr-xs" /> Stripe — Paiements
            </div>
            <div class="row q-col-gutter-md q-mb-md">
              <div class="col-12 col-md-4">
                <q-select v-model="settings.stripe_mode" label="Mode" outlined dense emit-value map-options
                  :options="[{ label: 'Test', value: 'test' }, { label: 'Live', value: 'live' }]"
                  @update:model-value="save('stripe_mode')" />
              </div>
              <div class="col-12 col-md-4">
                <q-input v-model="settings.stripe_publishable_key" label="Publishable Key" outlined dense
                  @blur="save('stripe_publishable_key')" />
              </div>
              <div class="col-12 col-md-4">
                <q-input v-model="settings.stripe_secret_key" label="Secret Key" outlined dense
                  type="password" @blur="save('stripe_secret_key')" />
              </div>
            </div>

            <q-separator class="q-my-md" />

            <div class="text-subtitle2 q-mb-xs">
              <q-icon name="map" size="18px" class="q-mr-xs" /> Mapbox
            </div>
            <div class="row q-col-gutter-md">
              <div class="col-12">
                <q-input v-model="settings.mapbox_token" label="Mapbox Token" outlined dense @blur="save('mapbox_token')" />
              </div>
            </div>
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 4: 3CX Phone -->
      <div class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7">
          <template #header>
            <SectionHeader icon="phone" label="3CX — Telephone WebRTC" />
          </template>
          <q-separator />
          <div class="q-pa-md">
            <div class="row q-col-gutter-md">
              <div class="col-12 col-md-6">
                <q-input v-model="phoneConfig.wssUrl" label="WSS URL (SBC)" outlined dense
                  placeholder="wss://targopbx.3cx.ca/wss" hint="WebSocket SBC endpoint" @blur="savePhone" />
              </div>
              <div class="col-12 col-md-6">
                <q-input v-model="phoneConfig.sipDomain" label="SIP Domain" outlined dense
                  placeholder="targopbx.3cx.ca" @blur="savePhone" />
              </div>
              <div class="col-12">
                <div class="text-caption text-grey-7 q-mb-xs">
                  Connectez-vous avec vos identifiants 3CX pour recuperer automatiquement vos credentials SIP.
                </div>
                <div class="row q-gutter-sm items-end">
                  <q-input v-model="pbxUsername" label="Email 3CX" outlined dense style="width:200px" />
                  <q-input v-model="pbxPassword" label="Mot de passe" outlined dense type="password" style="width:200px"
                    @keydown.enter="login3cx" />
                  <q-btn color="primary" label="Connecter" dense unelevated :loading="loggingIn3cx" @click="login3cx" />
                </div>
              </div>
              <div v-if="phoneConfig.extension" class="col-12">
                <div class="row q-gutter-md">
                  <q-input v-model="phoneConfig.extension" label="Extension" outlined dense readonly style="width:100px" />
                  <q-input v-model="phoneConfig.authId" label="Auth ID" outlined dense readonly style="width:160px" />
                  <q-input :model-value="phoneConfig.authPassword ? '--------' : ''" label="Auth Password" outlined dense readonly style="width:160px" />
                  <q-input v-model="phoneConfig.displayName" label="Nom" outlined dense readonly style="width:160px" />
                </div>
                <q-badge color="green" class="q-mt-xs">SIP credentials OK — Extension {{ phoneConfig.extension }}</q-badge>
              </div>
            </div>
            <div class="text-caption text-grey-6 q-mt-sm">
              Le SBC doit etre active dans 3CX Admin. <a href="https://targopbx.3cx.ca" target="_blank">3CX Admin</a>
            </div>
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 5: Reseau (OLT) -->
      <div v-if="can('view_clients')" class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7"
          @before-show="lazyFlags.network = true">
          <template #header>
            <SectionHeader icon="lan" label="Reseau — OLT / Fibre" />
          </template>
          <q-separator />
          <div class="q-pa-none">
            <NetworkPage v-if="lazyFlags.network" />
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 6: Telephonie (Fonoster/SIP) -->
      <div v-if="can('manage_telephony')" class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7"
          @before-show="lazyFlags.telephony = true">
          <template #header>
            <SectionHeader icon="phone_in_talk" label="Telephonie — SIP / Trunks" />
          </template>
          <q-separator />
          <div class="q-pa-none">
            <TelephonyPage v-if="lazyFlags.telephony" />
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 7: Agent AI Flows -->
      <div v-if="can('manage_settings')" class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7"
          @before-show="lazyFlags.agent = true">
          <template #header>
            <SectionHeader icon="smart_toy" label="Agent AI — Flows" />
          </template>
          <q-separator />
          <div class="q-pa-none">
            <AgentFlowsPage v-if="lazyFlags.agent" />
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 7b: Flow Templates (onboarding / service orchestration) -->
      <div v-if="can('manage_settings')" class="ops-card q-mb-md">
        <q-expansion-item header-class="section-header" expand-icon-class="text-grey-7"
          @before-show="lazyFlags.flows = true">
          <template #header>
            <SectionHeader icon="account_tree" label="Flows — Orchestration projets" />
          </template>
          <q-separator />
          <div class="q-pa-md">
            <FlowTemplatesSection v-if="lazyFlags.flows" />
          </div>
        </q-expansion-item>
      </div>

      <!-- SECTION 8: Liens rapides (console admin/infra — ERPNext desk, n8n, Authentik) : admins seulement (manage_settings) -->
      <div v-if="can('manage_settings')" class="ops-card">
        <q-expansion-item default-opened header-class="section-header" expand-icon-class="text-grey-7">
          <template #header>
            <SectionHeader icon="launch" label="Liens rapides" />
          </template>
          <q-separator />
          <div class="q-pa-md">
            <div class="row q-gutter-sm">
              <q-btn flat dense icon="open_in_new" label="ERPNext Desk" :href="erpDeskUrl" target="_blank" />
              <q-btn flat dense icon="open_in_new" label="Dispatch Settings" :href="erpDeskUrl + '/app/dispatch-settings'" target="_blank" />
              <q-btn flat dense icon="open_in_new" label="n8n" href="https://n8n.gigafibre.ca" target="_blank" />
              <q-btn flat dense icon="open_in_new" label="Authentik" href="https://auth.targo.ca" target="_blank" />
              <q-btn flat dense icon="open_in_new" label="Twilio Console" href="https://console.twilio.com" target="_blank" />
            </div>
          </div>
        </q-expansion-item>
      </div>
    </template>

    <!-- Modèles IA — routage par tâche + repli Gemini -->
    <AiRoutingCard v-if="can('manage_settings')" class="q-mt-md" />

    <!-- Délais SLA — réponse / résolution par file + priorité -->
    <SlaSettings v-if="can('manage_settings')" class="q-mt-md" />

    <!-- Départements omnichannel — abonnement PAR MEMBRE (une inscription = courriels + tickets + canaux). Vue primaire. -->
    <DepartmentSubscriptions v-if="can('manage_settings')" class="q-mt-md" />

    <!-- Files (Inbox) & équipes — vue PAR FILE (roster). Même store que les départements ci-dessus. -->
    <QueueTeamsCard class="q-mt-md" />

    <!-- Réponses pré-écrites (canned) — réutilisables dans l'Inbox -->
    <CannedResponsesCard class="q-mt-md" />
  </q-page>
</template>

<script setup>
import { ref, reactive, onMounted, watch, defineAsyncComponent, h, resolveComponent } from 'vue'
import { useRoute } from 'vue-router'
import { formatDateTimeShort as formatDate } from 'src/composables/useFormatters' // date+heure canonique (source unique)
import { Notify } from 'quasar'
import { authFetch } from 'src/api/auth'
import { BASE_URL, ERP_DESK_URL as erpDeskUrl } from 'src/config/erpnext'
import { sendTestSms } from 'src/api/sms'
import { getPhoneConfig, savePhoneConfig, fetch3cxCredentials } from 'src/composables/usePhone'
import { usePermissions } from 'src/composables/usePermissions'
import { usePermissionMatrix } from 'src/composables/usePermissionMatrix'
import { useUserGroups } from 'src/composables/useUserGroups'
import { useAvatar } from 'src/composables/useAvatar'
import UserAvatar from 'src/components/shared/UserAvatar.vue'
import EmployeeEditDialog from 'src/components/shared/EmployeeEditDialog.vue'
import IdentityManager from 'src/components/shared/IdentityManager.vue' // gestion des identités unifiées (label + alias courriel + lien tech + fusion)
import StaffConsole from 'src/components/shared/StaffConsole.vue' // réconciliation Authentik ↔ staff (provisionner/désactiver/supprimer gardé)
import { listDocs } from 'src/api/erp'
import QueueTeamsCard from 'src/components/settings/QueueTeamsCard.vue'
import DepartmentSubscriptions from 'src/components/settings/DepartmentSubscriptions.vue'
import CannedResponsesCard from 'src/components/settings/CannedResponsesCard.vue'
import AiRoutingCard from 'src/components/settings/AiRoutingCard.vue'
import SlaSettings from 'src/components/settings/SlaSettings.vue'
import { useLegacySync } from 'src/composables/useLegacySync'

const NetworkPage = defineAsyncComponent(() => import('src/pages/NetworkPage.vue'))
const TelephonyPage = defineAsyncComponent(() => import('src/pages/TelephonyPage.vue'))
const AgentFlowsPage = defineAsyncComponent(() => import('src/pages/AgentFlowsPage.vue'))
const FlowTemplatesSection = defineAsyncComponent(() => import('src/components/flow-editor/FlowTemplatesSection.vue'))

// Inline functional component for section headers
const QIcon = resolveComponent('QIcon')
const SectionHeader = (props) => h('div', { class: 'row items-center no-wrap', style: 'width:100%' }, [
  h(QIcon, { name: props.icon, size: props.icon === 'admin_panel_settings' ? '22px' : '20px', color: 'primary', class: 'q-mr-sm' }),
  h('span', { class: 'text-subtitle1 text-weight-bold' }, props.label),
])
SectionHeader.props = ['icon', 'label']

// Inline functional component for permission category grid
const PermGrid = (props, { slots }) => {
  const nodes = []
  for (const cat of props.categories) {
    nodes.push(h('div', { class: 'override-cat-label', key: cat + '-label' }, cat))
    const caps = props.capsByCategory[cat] || []
    nodes.push(h('div', { class: 'row q-gutter-xs flex-wrap q-mb-xs', key: cat + '-caps' },
      caps.map(cap => slots.cap({ cap }))
    ))
  }
  return h('div', { class: 'override-grid' }, nodes)
}
PermGrid.props = ['categories', 'capsByCategory']

const { can, isLoaded } = usePermissions()

const {
  permTab, permLoading, permSaving, permDirty,
  permGroups, permMatrix,
  allGroupNames, permCategories, permCapsByCategory,
  loadPerms, saveAllPerms, saveGroupPerms, countGroupPerms,
  effectivePerm, setUserOverride,
} = usePermissionMatrix()

const {
  userSearch, userResults, userSearchLoading, userSearchDone,
  selectedUser, savingGroups, savingName,
  selectedGroup, groupMembers, groupMembersLoading,
  addMemberSearch, memberSearchResults, memberSearchLoading,
  debouncedSearchUsers, searchUsers, selectUser, toggleUserGroup, saveUserName,
  selectGroup, loadGroupMembers, removeFromGroup,
  debouncedMemberSearch, addUserToCurrentGroup,
  inviteOpen, inviteSaving, inviteForm, lastInviteResult, openInviteDialog, submitInvite,
} = useUserGroups({ permGroups })

// ── Édition du nom complet (dans le panneau détail utilisateur) ──────────────
const editingName = ref(false)
const nameDraft = ref('')
function startEditName (user) {
  nameDraft.value = user.name || ''
  editingName.value = true
}
async function commitEditName (user) {
  const ok = await saveUserName(user, nameDraft.value)
  if (ok) editingName.value = false
}

// ── Profil employé lié au compte sélectionné (session ↔ Employee) ────────────
const selectedEmployee = ref(null)
const empResolving = ref(false)
const empDlgOpen = ref(false)
const empDlgName = ref('')
const empDlgLinkEmail = ref('')

async function resolveSelectedEmployee () {
  selectedEmployee.value = null
  const email = selectedUser.value?.email
  if (!email) return
  empResolving.value = true
  try {
    const fields = ['name', 'employee_name', 'designation', 'department', 'cell_number', 'office_extension', 'company_email', 'user_id']
    let rows = await listDocs('Employee', { filters: { user_id: email }, fields, limit: 1 })
    if (!rows.length) rows = await listDocs('Employee', { filters: { company_email: email }, fields, limit: 1 })
    selectedEmployee.value = rows[0] || null
  } catch { selectedEmployee.value = null } finally { empResolving.value = false }
}
watch(selectedUser, resolveSelectedEmployee)

function openEmpEdit (name) { empDlgLinkEmail.value = ''; empDlgName.value = name; empDlgOpen.value = true }
function openEmpLink (email) { empDlgName.value = ''; empDlgLinkEmail.value = email; empDlgOpen.value = true }
function onEmployeeSaved () { resolveSelectedEmployee() }

// ── Ouverture directe d'un utilisateur via ?user=<email> (bouton « Éditer »
// depuis la page Équipe). On force l'onglet Utilisateurs, on recherche par
// courriel puis on sélectionne la correspondance exacte.
const route = useRoute()
async function openUserByEmail (email) {
  const target = String(email || '').trim().toLowerCase()
  if (!target) return
  permTab.value = 'users'
  userSearch.value = target
  await searchUsers()
  const match = userResults.value.find(u => (u.email || '').toLowerCase() === target)
  if (match) selectUser(match)
  else Notify.create({ type: 'warning', message: `Aucun compte trouvé pour ${target}`, timeout: 3000 })
}

async function copyTempPassword () {
  if (!lastInviteResult.value?.temp_password) return
  try {
    await navigator.clipboard.writeText(lastInviteResult.value.temp_password)
    Notify.create({ type: 'positive', message: 'Mot de passe copié', timeout: 1500 })
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Impossible de copier: ' + e.message })
  }
}

const { legacySyncing, showSyncDialog, syncResult, syncLegacy } = useLegacySync({
  loadPerms, loadGroupMembers, selectedGroup,
})

// Lazy-load flags for embedded pages
const lazyFlags = reactive({ network: false, telephony: false, agent: false, flows: false })

// Page state
const loading = ref(true)
const settings = ref({})
const showToken = ref(false)
const testingSms = ref(false)
const smsTestResult = ref(null)

// 3CX Phone config
const phoneConfig = ref(getPhoneConfig())
const pbxUsername = ref('')
const pbxPassword = ref('')
const loggingIn3cx = ref(false)

// SMS template definitions
const smsTemplates = [
  { key: 'sms_enroute', label: 'Technicien en route' },
  { key: 'sms_completed', label: 'Service complete' },
  { key: 'sms_assigned', label: 'Job assigne (technicien)' },
]

function notify (msg, type = 'positive', timeout = 1500) {
  Notify.create({ type, message: msg, timeout })
}

// Avatar d'équipe : un admin peut définir la photo d'un membre (upload via ?as=).
const { uploadAvatar, fileToAvatarDataUrl } = useAvatar()
const teamAvatarInput = ref(null)
let teamAvatarTarget = null
function pickTeamAvatar (user) {
  teamAvatarTarget = user
  teamAvatarInput.value?.click()
}
async function onTeamAvatarFile (e) {
  const file = e.target.files && e.target.files[0]
  e.target.value = ''
  if (!file || !teamAvatarTarget) return
  try {
    const dataUrl = await fileToAvatarDataUrl(file)
    await uploadAvatar(dataUrl, { as: teamAvatarTarget.email })
  } catch (err) {
    Notify.create({ type: 'negative', message: 'Image illisible: ' + err.message })
  }
}

// formatDate → useFormatters.formatDateTimeShort (date+heure canonique)

function savePhone () {
  savePhoneConfig(phoneConfig.value)
  notify('Config telephone sauvegardee')
}

async function login3cx () {
  if (!pbxUsername.value || !pbxPassword.value) return
  loggingIn3cx.value = true
  try {
    const creds = await fetch3cxCredentials(pbxUsername.value, pbxPassword.value)
    Object.assign(phoneConfig.value, {
      extension: creds.extension,
      authId: creds.authId,
      authPassword: creds.authPassword,
      displayName: creds.displayName,
    })
    savePhoneConfig(phoneConfig.value)
    pbxPassword.value = ''
    notify(`Connecte — Extension ${creds.extension} (${creds.displayName})`, 'positive', 3000)
  } catch (e) {
    notify('3CX login echoue: ' + e.message, 'negative', 4000)
  } finally {
    loggingIn3cx.value = false
  }
}

// Snapshot for change detection
const snapshots = {}

onMounted(async () => {
  try {
    const res = await authFetch(BASE_URL + '/api/resource/Dispatch Settings/Dispatch Settings')
    if (!res.ok) throw new Error('Failed to load settings')
    const json = await res.json()
    settings.value = json.data
    for (const key of Object.keys(json.data)) {
      snapshots[key] = json.data[key] ?? ''
    }
  } catch (e) {
    notify('Erreur chargement parametres: ' + e.message, 'negative')
  } finally {
    loading.value = false
  }
  if (isLoaded.value && can('manage_permissions')) {
    loadPerms()
    if (route.query.user) openUserByEmail(String(route.query.user))
    else searchUsers()
  }
})

watch(isLoaded, (loaded) => {
  if (loaded && can('manage_permissions') && !permGroups.value.length) {
    loadPerms()
    if (route.query.user) openUserByEmail(String(route.query.user))
    else searchUsers()
  }
}, { immediate: false })

async function save (field) {
  const val = settings.value[field] ?? ''
  const prev = snapshots[field] ?? ''
  if (val === prev) return
  snapshots[field] = val
  try {
    const res = await authFetch(BASE_URL + '/api/resource/Dispatch Settings/Dispatch Settings', {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ [field]: val }),
    })
    if (!res.ok) throw new Error('Save failed: ' + res.status)
    notify('Sauvegarde')
  } catch (e) {
    notify('Erreur: ' + e.message, 'negative')
    settings.value[field] = prev
    snapshots[field] = prev
  }
}

async function testSms () {
  testingSms.value = true
  smsTestResult.value = null
  try {
    const result = await sendTestSms('+15149490739', 'Test SMS depuis Targo Ops', '')
    smsTestResult.value = { ok: true, message: result.simulated ? 'Simule (pas envoye)' : 'SMS envoye' }
  } catch (e) {
    smsTestResult.value = { ok: false, message: e.message }
  } finally {
    testingSms.value = false
  }
}
</script>

<style scoped>
.section-header { padding: 12px 16px; }

.perm-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.perm-table th, .perm-table td { padding: 4px 8px; border-bottom: 1px solid #e2e8f0; }
.perm-cap-col { text-align: left; min-width: 200px; }
.perm-group-col { text-align: center; min-width: 90px; white-space: nowrap; }
.perm-cat-row td { padding-top: 12px; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.5px; }
.perm-cap-label { color: #475569; }
.perm-matrix { overflow-x: auto; }

.perm-override-chip { display: inline-flex; align-items: center; gap: 2px; padding: 2px 6px; border-radius: 4px; margin: 2px; background: #f1f5f9; }
.perm-override-on { background: #fef3c7; }
.perm-override-off { background: #fee2e2; }
.override-cat-label { font-size: 0.72rem; font-weight: 700; color: #6b7280; text-transform: uppercase; letter-spacing: 0.5px; margin-top: 8px; margin-bottom: 2px; }

.user-list { max-height: 360px; overflow-y: auto; border: 1px solid #e2e8f0; border-radius: 8px; }
.user-card { padding: 10px 14px; border-bottom: 1px solid #f1f5f9; cursor: pointer; transition: background 0.15s; }
.user-card:last-child { border-bottom: none; }
.user-card:hover { background: #f8fafc; }
.user-card--selected { background: #eef2ff; border-left: 3px solid #6366f1; }

.user-detail-panel { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 16px; }
.ua-edit { position: relative; display: inline-flex; }
.ua-edit--can { cursor: pointer; }
.ua-edit__cam { position: absolute; right: -2px; bottom: -2px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--ops-primary, #16a34a); display: flex; align-items: center; justify-content: center;
  border: 2px solid #fff; }

.group-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.group-card { padding: 14px; border: 1px solid #e2e8f0; border-radius: 10px; cursor: pointer; transition: all 0.15s; }
.group-card:hover { border-color: #6366f1; background: #fafafe; }
.group-card--selected { border-color: #6366f1; background: #eef2ff; box-shadow: 0 0 0 1px #6366f1; }
.group-detail-panel { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 16px; }

.effective-perms .q-badge { margin: 1px; }

:deep(.q-page) { min-height: auto !important; padding: 12px !important; }

.member-search-dropdown {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 10;
  background: white; border: 1px solid #e2e8f0; border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1); max-height: 240px; overflow-y: auto;
}
.member-search-item {
  display: flex; align-items: center; padding: 8px 12px; cursor: pointer;
  border-bottom: 1px solid #f1f5f9; font-size: 0.85rem;
}
.member-search-item:last-child { border-bottom: none; }
.member-search-item:hover { background: #f1f5f9; }
/* Surlignage de la ligne membre au survol → on vise sans erreur le bon bouton « Retirer » dans une longue liste */
.member-row { border-bottom: 1px solid #f1f5f9; border-radius: 6px; transition: background .1s; }
.member-row:hover { background: #eff3ff; box-shadow: inset 3px 0 0 #6366f1; }
.member-row .member-row-del { opacity: .45; transition: opacity .1s; }
.member-row:hover .member-row-del { opacity: 1; }
</style>
