<template>
  <q-page class="q-pa-md">
    <PageHeader title="Événements" />

    <!-- Bandeau événement + sélecteur -->
    <div class="ops-card q-pa-md q-mb-md" style="border-radius:12px">
      <div class="row items-center ops-row-wrap q-gutter-sm">
        <div class="ev-badge">
          <template v-if="ev.badge_top || ev.badge_bottom"><b>{{ ev.badge_top || '🎉' }}</b><span v-if="ev.badge_bottom">{{ ev.badge_bottom }}</span></template>
          <span v-else style="font-size:1.4rem">🎉</span>
        </div>
        <div class="col" style="min-width:180px">
          <q-select v-if="events.length > 1" dense borderless v-model="eventId" :options="eventOptions" emit-value map-options
            class="text-h6 text-weight-bold" @update:model-value="onSelectEvent" popup-content-class="text-body1" />
          <div v-else class="text-h6 text-weight-bold ellipsis">{{ ev.name || '—' }}</div>
          <div class="text-caption text-grey-7">
            <q-icon name="event" size="16px" class="q-mr-xs" />{{ ev.when || '—' }}
            <span v-if="ev.capacity" class="q-ml-sm"><q-icon name="groups" size="16px" class="q-mr-xs" />plafond {{ ev.capacity }} pers.</span>
          </div>
        </div>
        <q-btn flat dense no-caps icon="edit" label="Modifier" @click="openEdit" class="col-auto" :disable="!eventId" />
        <q-btn unelevated dense no-caps color="primary" icon="add" label="Nouvel événement" @click="openCreate" class="col-auto" />
        <q-btn flat dense round icon="refresh" :loading="loading" @click="load" class="col-auto"><q-tooltip>Rafraîchir</q-tooltip></q-btn>
      </div>
    </div>

    <!-- KPIs -->
    <div class="row q-col-gutter-sm q-mb-md">
      <div class="col-6 col-sm-4"><StatCard label="Inscriptions" :value="count" icon="how_to_reg" color="primary" hint="Réponses reçues" /></div>
      <div class="col-6 col-sm-4">
        <StatCard label="Personnes attendues" :value="capacityLabel" icon="groups" :color="isFull ? 'red-7' : 'green-7'"
          :value-class="isFull ? 'text-red-7' : ''" :hint="ev.capacity ? (isFull ? 'COMPLET — formulaire fermé' : 'Total / plafond') : 'Total pour le food truck'" />
      </div>
      <div class="col-6 col-sm-4"><StatCard label="À vérifier" :value="unmatched" icon="help_outline" :color="unmatched ? 'orange-8' : 'grey-5'" :value-class="unmatched ? 'text-orange-8' : ''" hint="N° client non reconnu" /></div>
    </div>

    <div class="row q-col-gutter-md">
      <!-- Colonne gauche : inviter -->
      <div class="col-12 col-md-4">
        <div class="ops-card q-pa-md q-mb-md" style="border-radius:12px">
          <div class="text-subtitle2 text-weight-bold q-mb-sm"><q-icon name="link" class="q-mr-xs" />Lien public d'inscription</div>
          <div class="text-caption text-grey-7 q-mb-sm">À mettre sur l'affiche, les réseaux sociaux ou un code QR. Le client saisit son numéro.</div>
          <q-input dense outlined readonly :model-value="publicUrl" class="q-mb-sm">
            <template #append><q-btn flat dense round icon="content_copy" @click="copy(publicUrl)"><q-tooltip>Copier</q-tooltip></q-btn></template>
          </q-input>
          <q-btn flat dense no-caps color="primary" icon="open_in_new" label="Ouvrir la page" :href="publicUrl" target="_blank" :disable="!publicUrl" />
        </div>

        <div class="ops-card q-pa-md" style="border-radius:12px">
          <div class="text-subtitle2 text-weight-bold q-mb-sm"><q-icon name="mail" class="q-mr-xs" />Invitation par courriel</div>
          <div class="text-caption text-grey-7 q-mb-sm">
            Chaque client reçoit un lien <b>personnalisé</b> : son numéro est pré-rempli et son inscription est rattachée automatiquement.
          </div>
          <div v-if="attachments.length" class="text-caption text-grey-7 q-mb-sm">
            <q-icon name="attach_file" size="14px" /> {{ attachments.length }} pièce(s) jointe(s) au courriel
          </div>
          <q-btn unelevated no-caps color="primary" icon="send" label="Préparer l'envoi" @click="prepSend" />
          <div class="text-caption text-grey-5 q-mt-sm">Aucun courriel n'est envoyé sans confirmation.</div>
        </div>
      </div>

      <!-- Colonne droite : liste des inscrits -->
      <div class="col-12 col-md-8">
        <div class="ops-card q-pa-md" style="border-radius:12px">
          <div class="row items-center ops-row-wrap q-mb-sm">
            <div class="text-subtitle2 text-weight-bold">Inscriptions</div>
            <q-space />
            <q-btn flat dense no-caps icon="download" label="CSV" :disable="!filtered.length" @click="exportRows" />
          </div>
          <DynamicFilter v-model="filterState" dense search-placeholder="Nom, n° client, courriel…"
            :chip-groups="chipGroups" :filtered-count="filtered.length" class="q-mb-sm" />

          <q-banner v-if="error" dense rounded class="bg-orange-1 text-orange-9 q-mb-sm">
            <template #avatar><q-icon name="cloud_off" /></template>
            {{ error }}
          </q-banner>

          <DataTable
            :rows="filtered" :columns="columns" row-key="key"
            flat bordered dense :loading="loading"
            :pagination="{ rowsPerPage: 50, sortBy: 'updated', descending: true }"
            no-data-label="Aucune inscription pour l'instant.">
            <template #body-cell-client="props">
              <q-td :props="props">
                <router-link v-if="props.row.customer_id" :to="'/clients/' + encodeURIComponent(props.row.customer_id)" class="text-weight-medium ellipsis erp-link" style="display:block">{{ props.row.customer_name || props.row.customer_number || '—' }}</router-link>
                <div v-else class="text-weight-medium ellipsis">{{ props.row.customer_name || props.row.customer_number || '—' }}</div>
                <div class="text-caption text-grey-6">{{ props.row.customer_number }}</div>
              </q-td>
            </template>
            <template #body-cell-party="props">
              <q-td :props="props" class="text-center"><q-chip dense square color="green-1" text-color="green-9" class="text-weight-bold">{{ props.value }}</q-chip></q-td>
            </template>
            <template #body-cell-email="props">
              <q-td :props="props">
                <div>{{ props.value || '—' }}</div>
                <div v-if="props.row.phone" class="text-caption text-grey-7"><q-icon name="call" size="12px" class="q-mr-xs" />{{ props.row.phone }}</div>
              </q-td>
            </template>
            <template #body-cell-allergies="props">
              <q-td :props="props">
                <span v-if="props.value" class="text-orange-9">⚠ {{ props.value }}</span>
                <span v-else class="text-grey-5">—</span>
              </q-td>
            </template>
            <template #body-cell-confidence="props">
              <q-td :props="props" class="text-center">
                <q-badge v-if="props.value === 'confirmed'" color="green-7" label="Confirmé"><q-tooltip>≥2 infos concordent : {{ (props.row.signals || []).join(', ') }}</q-tooltip></q-badge>
                <q-badge v-else-if="props.value === 'probable'" color="blue-6" label="Probable"><q-tooltip>1 info concorde : {{ (props.row.signals || []).join(', ') }} — à confirmer</q-tooltip></q-badge>
                <q-badge v-else color="orange-7" label="À vérifier"><q-tooltip>Aucune concordance — valider manuellement</q-tooltip></q-badge>
                <div v-if="props.row.account_name && props.row.account_name !== props.row.customer_name" class="text-caption text-grey-6 q-mt-xs">dossier : {{ props.row.account_name }}</div>
              </q-td>
            </template>
            <template #body-cell-updated="props">
              <q-td :props="props" class="text-caption">{{ fmtDate(props.value) }}</q-td>
            </template>
            <template #body-cell-actions="props">
              <q-td :props="props" class="text-center">
                <q-btn flat dense round size="sm" icon="delete" color="negative" @click="confirmDelete(props.row)"><q-tooltip>Retirer</q-tooltip></q-btn>
              </q-td>
            </template>
          </DataTable>
        </div>
      </div>
    </div>

    <!-- Dialogue de création / édition d'un événement -->
    <q-dialog v-model="showForm" persistent>
      <q-card style="min-width:340px;max-width:720px;width:100%">
        <q-card-section class="row items-center q-pb-none">
          <div class="text-h6">{{ formMode === 'create' ? 'Nouvel événement' : 'Modifier l\'événement' }}</div><q-space />
          <q-btn flat round dense icon="close" v-close-popup />
        </q-card-section>

        <q-card-section style="max-height:70vh;overflow:auto">
          <div class="row q-col-gutter-sm">
            <q-input class="col-12 col-sm-8" v-model="form.fr.name" dense outlined label="Nom de l'événement *" hint="Requis" />
            <q-input class="col-6 col-sm-4" v-model="form.date_iso" dense outlined type="date" label="Date" stack-label />
          </div>
          <div class="row q-col-gutter-sm q-mt-none">
            <q-input class="col-4 col-sm-2" v-model="form.badge_top" dense outlined label="Badge (haut)" maxlength="6" hint="ex. 20" />
            <q-input class="col-8 col-sm-3" v-model="form.badge_bottom" dense outlined label="Badge (bas)" maxlength="8" hint="ex. ANS" />
            <q-input class="col-6 col-sm-4" v-model.number="form.capacity" dense outlined type="number" min="0" label="Plafond (personnes)" hint="0 = illimité">
              <template #prepend><q-icon name="groups" /></template>
            </q-input>
            <div class="col-6 col-sm-3 flex items-center"><q-toggle v-model="form.active" label="Actif" /></div>
          </div>

          <q-tabs v-model="formLang" dense class="text-grey-8 q-mt-md" active-color="primary" indicator-color="primary" align="left" narrow-indicator>
            <q-tab name="fr" label="Français" />
            <q-tab name="en" label="English (optionnel)" />
          </q-tabs>
          <q-separator />
          <q-tab-panels v-model="formLang" animated class="bg-transparent">
            <q-tab-panel v-for="lg in ['fr', 'en']" :key="lg" :name="lg" class="q-px-none q-gutter-sm">
              <div v-if="lg === 'en'" class="text-caption text-grey-6">Laissez vide pour reprendre le texte français automatiquement.</div>
              <q-input v-if="lg === 'en'" v-model="form.en.name" dense outlined label="Name" />
              <q-input v-model="form[lg].tagline" dense outlined autogrow label="Accroche" />
              <q-input v-model="form[lg].when" dense outlined :label="lg === 'fr' ? 'Quand (texte)' : 'When (text)'" hint="ex. 1ᵉʳ août, de 10 h à 15 h" />
              <q-input v-model="form[lg].address" dense outlined :label="lg === 'fr' ? 'Adresse (texte, optionnel)' : 'Address (text, optional)'" hint="ex. À nos bureaux : 1867 chemin de la rivière, Ste-Clotilde">
                <template #prepend><q-icon name="place" /></template>
              </q-input>
              <q-input v-model="form[lg].body" dense outlined type="textarea" autogrow :label="lg === 'fr' ? 'Texte d\'invitation' : 'Invitation text'" />

              <div class="text-weight-medium text-grey-8 q-mt-sm">Programme</div>
              <div v-for="(p, i) in form[lg].program" :key="i" class="row q-col-gutter-xs items-center">
                <q-input class="col-2" v-model="p.icon" dense outlined label="Icône" maxlength="4" />
                <q-input class="col" v-model="p.label" dense outlined label="Libellé" />
                <q-input class="col-3" v-model="p.sub" dense outlined label="Détail" />
                <q-btn class="col-auto" flat dense round icon="close" color="grey-7" @click="form[lg].program.splice(i, 1)" />
              </div>
              <q-btn flat dense no-caps size="sm" icon="add" label="Ajouter un élément" color="primary" @click="form[lg].program.push({ icon: '', label: '', sub: '' })" />

              <q-input v-model="form[lg].program_line" dense outlined class="q-mt-sm" :label="lg === 'fr' ? 'Ligne sous le programme' : 'Line under program'" />
              <q-input v-model="form[lg].limited" dense outlined type="textarea" autogrow :label="lg === 'fr' ? 'Encadré « places limitées »' : 'Limited-space note'" />
              <q-input v-model="form[lg].closing" dense outlined :label="lg === 'fr' ? 'Phrase de clôture' : 'Closing line'" />

              <div class="text-weight-medium text-grey-8 q-mt-sm">Notes de bas de page</div>
              <div v-for="(n, i) in form[lg].notes" :key="'n' + i" class="row q-col-gutter-xs items-center">
                <q-input class="col" v-model="form[lg].notes[i]" dense outlined :label="'Note ' + (i + 1)" />
                <q-btn class="col-auto" flat dense round icon="close" color="grey-7" @click="form[lg].notes.splice(i, 1)" />
              </div>
              <q-btn flat dense no-caps size="sm" icon="add" label="Ajouter une note" color="primary" @click="form[lg].notes.push('')" />
            </q-tab-panel>
          </q-tab-panels>

          <!-- Modèle de courriel d'invitation — festif intégré OU template éditable (Unlayer, comme les campagnes) -->
          <q-separator class="q-my-md" />
          <div class="text-weight-medium text-grey-8 q-mb-xs"><q-icon name="mail" size="18px" /> Modèle du courriel d'invitation</div>
          <q-select v-model="form.email_template" :options="emailTemplateOptions" emit-value map-options dense outlined
            label="Modèle" hint="« Festif intégré » = charte TARGO verrouillée. Un template éditable se conçoit dans l'éditeur (glisser-déposer)." />
          <div class="row q-gutter-sm q-mt-xs">
            <template v-if="formMode === 'edit'">
              <q-btn outline no-caps size="sm" color="primary" icon="visibility" label="Aperçu" :loading="previewLoading" @click="openInvitePreview" />
              <q-btn v-if="form.email_template" flat no-caps size="sm" color="primary" icon="brush" label="Concevoir dans l'éditeur"
                type="a" :href="'/ops/#/campaigns/templates/' + form.email_template" target="_blank">
                <q-tooltip>Ouvre l'éditeur glisser-déposer (nouvel onglet). Variables : firstname, rsvp_url.</q-tooltip>
              </q-btn>
            </template>
            <div v-else class="text-caption text-grey-6">Aperçu et conception disponibles après la création.</div>
          </div>

          <!-- Pièces jointes (courriel) — seulement en édition (l'événement doit exister) -->
          <template v-if="formMode === 'edit'">
            <q-separator class="q-my-md" />
            <div class="text-weight-medium text-grey-8 q-mb-xs"><q-icon name="attach_file" size="18px" /> Pièces jointes au courriel d'invitation</div>
            <div class="text-caption text-grey-6 q-mb-sm">Images (PNG/JPG/GIF/WebP) ou PDF, max 4 Mo · jusqu'à 6 fichiers. Chaque client reçoit les fichiers de <b>sa langue</b> (+ les fichiers « Les deux »).</div>
            <q-list bordered separator class="rounded-borders q-mb-sm" v-if="attachments.length">
              <q-item v-for="a in attachments" :key="a.stored" dense>
                <q-item-section avatar><q-icon :name="/pdf/.test(a.mime) ? 'picture_as_pdf' : 'image'" color="grey-7" /></q-item-section>
                <q-item-section><q-item-label>{{ a.filename }}</q-item-label><q-item-label caption>{{ (a.size / 1024).toFixed(0) }} Ko</q-item-label></q-item-section>
                <q-item-section side><q-badge :color="attLangColor(a.lang)" :label="attLangLabel(a.lang)" /></q-item-section>
                <q-item-section side><q-btn flat dense round icon="delete" color="negative" @click="removeAtt(a)" /></q-item-section>
              </q-item>
            </q-list>
            <div class="row q-col-gutter-sm items-center">
              <q-select class="col-12 col-sm-5" v-model="attLang" dense outlined label="Langue du fichier"
                :options="[{ label: 'Français', value: 'fr' }, { label: 'English', value: 'en' }, { label: 'Les deux', value: 'both' }, { label: 'Détecter (Gemini)', value: 'auto' }]"
                emit-value map-options />
              <q-file class="col" v-model="attFile" dense outlined label="Ajouter une pièce jointe" accept="image/*,application/pdf" :loading="uploadingAtt" @update:model-value="onAttFile">
                <template #prepend><q-icon name="upload_file" /></template>
              </q-file>
            </div>
          </template>
        </q-card-section>

        <q-card-actions align="right">
          <q-btn v-if="formMode === 'edit'" flat no-caps color="negative" icon="delete" label="Supprimer" @click="confirmDeleteEvent" />
          <q-space />
          <q-btn flat no-caps label="Annuler" v-close-popup />
          <q-btn unelevated no-caps color="primary" :label="formMode === 'create' ? 'Créer' : 'Enregistrer'" :loading="savingForm" @click="saveForm" />
        </q-card-actions>
      </q-card>
    </q-dialog>

    <!-- Aperçu de l'invitation (rendu HTML, échantillon de variables) -->
    <q-dialog v-model="invitePreviewOpen" maximized>
      <q-card class="bg-grey-2">
        <q-toolbar class="bg-white" style="border-bottom:1px solid #e5e7eb">
          <q-icon name="visibility" class="q-mr-sm" />
          <q-toolbar-title>Aperçu de l'invitation</q-toolbar-title>
          <q-btn-toggle v-model="invitePreviewLang" dense no-caps unelevated toggle-color="primary" color="grey-3" text-color="grey-8"
            :options="[{ label: 'FR', value: 'fr' }, { label: 'EN', value: 'en' }]" @update:model-value="loadInvitePreview" class="q-mr-sm" />
          <q-btn flat dense round icon="close" v-close-popup />
        </q-toolbar>
        <q-card-section style="height:calc(100vh - 60px);overflow:hidden">
          <iframe :srcdoc="invitePreviewHtml" style="width:100%;height:100%;border:1px solid #e5e7eb;background:#fff" />
        </q-card-section>
      </q-card>
    </q-dialog>

    <!-- Dialogue d'envoi : test OU audience de masse (aperçu ; le blast reste à activer) -->
    <q-dialog v-model="showSend">
      <q-card style="min-width:340px;max-width:560px;width:100%">
        <q-card-section class="row items-center q-pb-none">
          <div class="text-h6">Envoyer une invitation</div><q-space />
          <q-btn flat round dense icon="close" v-close-popup />
        </q-card-section>

        <q-card-section class="q-pb-none">
          <q-btn-toggle v-model="sendMode" spread no-caps unelevated toggle-color="primary" color="grey-3" text-color="grey-8"
            :options="[{ label: 'Test à moi', value: 'test' }, { label: 'Envoi de masse', value: 'mass' }]" />
        </q-card-section>

        <!-- TEST -->
        <q-card-section v-if="sendMode === 'test'" class="q-gutter-sm">
          <div class="text-caption text-grey-7">Envoi d'un test (courriel avec lien personnalisé{{ attachments.length ? ' + pièces jointes de la langue choisie' : '' }}) à ton adresse.</div>
          <q-btn-toggle v-model="sendChannel" spread no-caps dense :options="[{ label: 'Mailjet (suivi)', value: 'mailjet' }, { label: 'Gmail direct', value: 'gmail' }]" />
          <q-btn-toggle v-model="testLang" spread no-caps dense :options="[{ label: 'Français', value: 'fr' }, { label: 'English', value: 'en' }]" />
          <q-input v-model="testEmail" dense outlined type="email" label="Courriel de test" autofocus />
        </q-card-section>

        <!-- MASSE -->
        <q-card-section v-else class="q-gutter-sm">
          <div class="text-caption text-grey-7">
            <q-icon name="mail" size="14px" /> Modèle : <b>{{ ev.email_template || 'Festif intégré (TARGO)' }}</b> — se change/conçoit dans « Modifier ».
          </div>
          <q-btn-toggle v-model="sendChannel" spread no-caps dense :options="[{ label: 'Mailjet (suivi)', value: 'mailjet' }, { label: 'Gmail direct', value: 'gmail' }]" />
          <div class="text-caption text-grey-7"><q-icon name="info" size="14px" /> Mailjet = suivi ouvertures/clics. Gmail direct = aucun suivi.</div>
          <div v-if="attachments.length" class="text-caption text-grey-7"><q-icon name="attach_file" size="14px" /> {{ attachments.length }} pièce(s) jointe(s) — gérées dans « Modifier ».</div>

          <!-- LISTE PRINCIPALE (additive, persistée) -->
          <div class="ops-card q-pa-sm" style="border-radius:10px;border:1px solid var(--ops-border,#e0e0e0)">
            <div class="row items-center">
              <div class="text-subtitle2 text-weight-bold"><q-icon name="list_alt" class="q-mr-xs" />Liste d'envoi : {{ mainList.count }} destinataire(s)</div>
              <q-space />
              <q-btn v-if="mainList.count" flat dense no-caps size="sm" color="negative" icon="delete_sweep" label="Vider" :loading="listBusy" @click="clearList" />
            </div>
            <div v-if="mainListSources.length" class="q-mt-xs">
              <q-chip v-for="s in mainListSources" :key="s.label" dense square size="sm" color="blue-1" text-color="blue-10">{{ s.label }} · {{ s.n }}</q-chip>
            </div>
            <div v-if="mainList.count" class="q-mt-xs">
              <a class="cursor-pointer text-caption text-primary" @click="showListSample = !showListSample">{{ showListSample ? '▾ Masquer' : '▸ Voir' }} les destinataires</a>
              <q-list v-if="showListSample" dense separator bordered class="rounded-borders q-mt-xs" style="max-height:200px;overflow:auto">
                <q-item v-for="r in mainList.sample" :key="r.email" dense>
                  <q-item-section>
                    <q-item-label class="text-caption">{{ r.name }} <q-badge dense :color="r.language === 'en' ? 'deep-orange-6' : 'blue-6'" :label="(r.language || 'fr').toUpperCase()" class="q-ml-xs" /></q-item-label>
                    <q-item-label caption>{{ r.email }}<span v-if="r.source"> · {{ r.source }}</span></q-item-label>
                  </q-item-section>
                  <q-item-section side><q-btn flat dense round size="sm" icon="close" @click="removeFromList(r)" /></q-item-section>
                </q-item>
                <q-item v-if="mainList.count > mainList.sample.length" dense><q-item-section class="text-caption text-grey-6">…et {{ mainList.count - mainList.sample.length }} autres (affichage plafonné à 200)</q-item-section></q-item>
              </q-list>
            </div>
            <div v-else class="text-caption text-grey-6 q-mt-xs">Ajoutez des lots ci-dessous (par filtre, sélection ou CSV). Ils s'additionnent ici, sans doublon.</div>
          </div>

          <div class="text-weight-medium text-grey-8 q-mt-sm">Ajouter des destinataires</div>
          <q-btn-toggle v-model="audienceSource" spread no-caps dense
            :options="[{ label: 'Par filtre', value: 'list' }, { label: 'Sélection', value: 'manual' }, { label: 'CSV', value: 'csv' }]" />

          <div v-if="audienceSource === 'list'" class="q-gutter-sm">
            <div class="row q-col-gutter-sm">
              <q-select class="col-12 col-sm-6" v-model="audFilters.statut" :options="[{ label: 'Clients actifs', value: 'active' }, { label: 'Tous (incl. résiliés)', value: '' }]" dense outlined emit-value map-options label="Statut" />
              <q-select class="col-12 col-sm-6" v-model="audFilters.customer_type" :options="[{ label: 'Tous types', value: '' }, { label: 'Résidentiel', value: 'Individual' }, { label: 'Commercial', value: 'Company' }]" dense outlined emit-value map-options label="Type de client" />
            </div>
            <div class="row q-col-gutter-sm">
              <q-input class="col-12 col-sm-6" v-model="audFilters.city" dense outlined clearable label="Ville" placeholder="ex. Gatineau">
                <template #prepend><q-icon name="location_city" /></template>
              </q-input>
              <q-input class="col-12 col-sm-6" v-model="audFilters.name_like" dense outlined clearable label="Nom du compte contient" placeholder="ex. Proprio">
                <template #prepend><q-icon name="search" /></template>
              </q-input>
            </div>
            <q-toggle v-model="audFilters.active_sub" label="Abonnement actif seulement" @update:model-value="onActiveSubToggle" />
            <q-input v-model.number="audFilters.min_monthly" type="number" min="0" dense outlined :disable="!audFilters.active_sub" label="Total mensuel minimum ($/mois)">
              <template #prepend><q-icon name="attach_money" /></template>
            </q-input>
            <div class="text-caption text-grey-6">« Ville » filtre par lieu de service ; « Nom contient » par sous-chaîne. Les critères se combinent (ET). Le « total mensuel » requiert « Abonnement actif ».</div>
            <q-btn unelevated no-caps color="primary" icon="playlist_add" label="Ajouter ces clients à la liste" :loading="listBusy" @click="addFilterToList" />
          </div>

          <div v-else-if="audienceSource === 'manual'" class="q-gutter-sm">
            <q-input v-model="poolQuery" dense outlined clearable debounce="300" :loading="poolSearching"
              label="Rechercher un client (nom, n°, courriel)…" @update:model-value="onPoolSearch">
              <template #prepend><q-icon name="person_search" /></template>
            </q-input>
            <!-- Résultats en temps réel : cliquer « + » ajoute au lot, la liste reste affichée -->
            <q-list v-if="poolResults.length" bordered separator class="rounded-borders" style="max-height:200px;overflow:auto">
              <q-item v-for="m in poolResults" :key="m.customer_id" dense>
                <q-item-section>
                  <q-item-label>{{ m.customer_name }}<q-badge v-if="m.matched" dense color="grey-4" text-color="grey-8" :label="m.matched" class="q-ml-xs" /></q-item-label>
                  <q-item-label caption>{{ m.customer_id }}<span v-if="m.email"> · {{ m.email }}</span><span v-else class="text-orange-8"> · sans courriel</span></q-item-label>
                </q-item-section>
                <q-item-section side>
                  <q-btn flat dense round size="sm" :icon="inPool(m) ? 'check' : 'add'" :color="inPool(m) ? 'green-7' : 'primary'" :disable="inPool(m)" @click="addToPool(m)">
                    <q-tooltip>{{ inPool(m) ? 'Déjà dans le lot' : 'Ajouter au lot' }}</q-tooltip>
                  </q-btn>
                </q-item-section>
              </q-item>
            </q-list>
            <div v-else-if="(poolQuery || '').trim().length >= 2 && !poolSearching" class="text-caption text-grey-6">Aucun résultat pour « {{ poolQuery }} ».</div>
            <div v-else-if="!pool.length" class="text-caption text-grey-6">Tapez au moins 2 caractères. Recherche floue (tolère les fautes et accents).</div>

            <div v-if="pool.length" class="q-gutter-xs q-pt-xs">
              <div class="text-caption text-weight-medium text-grey-8">Lot sélectionné : {{ pool.length }}</div>
              <q-list bordered separator class="rounded-borders" style="max-height:150px;overflow:auto">
                <q-item v-for="p in pool" :key="p.customer_id" dense>
                  <q-item-section>
                    <q-item-label>{{ p.customer_name || p.customer_id }}</q-item-label>
                    <q-item-label caption>{{ p.customer_id }}<span v-if="p.email"> · {{ p.email }}</span><span v-else class="text-orange-8"> · sans courriel (sera ignoré)</span></q-item-label>
                  </q-item-section>
                  <q-item-section side><q-btn flat dense round size="sm" icon="close" @click="removeFromPool(p)" /></q-item-section>
                </q-item>
              </q-list>
              <q-btn unelevated no-caps color="primary" icon="playlist_add" :label="`Ajouter les ${pool.length} sélectionné(s) à la liste`" :loading="listBusy" @click="addManualToList" />
            </div>
          </div>

          <div v-else class="q-gutter-sm">
            <q-file v-model="csvFile" dense outlined label="Fichier CSV" accept=".csv,text/csv" @update:model-value="onCsvFile">
              <template #prepend><q-icon name="upload_file" /></template>
            </q-file>
            <div class="text-caption text-grey-6">Colonne obligatoire : <b>email</b>. Optionnelles : firstname, lastname, language (fr/en), customer_id, phone.</div>
            <q-btn unelevated no-caps color="primary" icon="playlist_add" label="Ajouter le CSV à la liste" :disable="!audCsvText" :loading="listBusy" @click="addCsvToList" />
          </div>

          <q-separator class="q-my-sm" />
          <q-banner dense rounded class="bg-blue-1 text-blue-10">
            <template #avatar><q-icon name="insights" color="blue-8" /></template>
            L'envoi crée une campagne : suivi ouvertures/clics (Mailjet), statut par destinataire et rapport dans <a class="text-primary cursor-pointer text-weight-medium" @click="goCampaigns">Campagnes</a>.
          </q-banner>
        </q-card-section>

        <q-card-actions align="right">
          <q-btn flat no-caps label="Fermer" v-close-popup />
          <q-btn v-if="sendMode === 'test'" unelevated no-caps color="primary" icon="send" label="Envoyer un test" :loading="sending" @click="sendTestNow" />
          <q-btn v-else unelevated no-caps color="negative" icon="send" :disable="!mainList.count || sendingMass" :loading="sendingMass"
            :label="mainList.count ? `Envoyer à ${mainList.count} destinataire(s)` : 'Liste vide'" @click="confirmMassSend" />
        </q-card-actions>
      </q-card>
    </q-dialog>
  </q-page>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { useQuasar } from 'quasar'
import PageHeader from 'src/components/shared/PageHeader.vue'
import StatCard from 'src/components/shared/StatCard.vue'
import DataTable from 'src/components/shared/DataTable.vue'
import DynamicFilter from 'src/components/shared/DynamicFilter.vue'
import { formatDateTimeShort as fmtDate } from 'src/composables/useFormatters'
import { useCsvExport } from 'src/composables/useCsvExport'
import { usePermissions } from 'src/composables/usePermissions'
import {
  listEvents, listRsvps, deleteRsvp, sendInvite, listTemplates,
  getEventConfig, createEvent, updateEvent, deleteEvent, uploadAttachment, deleteAttachment,
  getAudienceList, audienceListAdd, audienceListRemove, audienceListClear, searchCustomersFuzzy,
  getInvitePreview,
} from 'src/api/events'

const $q = useQuasar()
const { exportCsv } = useCsvExport()

const loading = ref(false)
const error = ref('')
const events = ref([])
const eventId = ref('')
const ev = ref({})
const attachments = ref([])
const rows = ref([])
const count = ref(0)
const headcount = ref(0)
const matched = ref(0)
const unmatched = ref(0)

const { userEmail } = usePermissions()
const showSend = ref(false)
const sendChannel = ref('mailjet')
const testEmail = ref('')
const testLang = ref('fr')
const sending = ref(false)
// Envoi de masse (audience + modèle) — aperçu seulement ; le blast reste à activer.
const sendMode = ref('test')
const templates = ref([{ value: '', label: 'Invitation Fête 20 ans (TARGO)' }])
const audienceSource = ref('list')
const audFilters = ref({ statut: 'active', customer_type: '', city: '', name_like: '', active_sub: false, min_monthly: 0 })
const csvFile = ref(null)
const audCsvText = ref('')
// Pool manuel : recherche temps réel → résultats → sélection avant ajout à la liste
const pool = ref([])
const poolQuery = ref('')
const poolResults = ref([])
const poolSearching = ref(false)
// Liste principale (additive, persistée côté hub)
const mainList = ref({ count: 0, by_source: {}, sample: [], updated: '' })
const listBusy = ref(false)
const showListSample = ref(false)

const mainListSources = computed(() => Object.entries(mainList.value.by_source || {}).map(([label, n]) => ({ label, n })).sort((a, b) => b.n - a.n))
const eventOptions = computed(() => events.value.map(e => ({ value: e.id, label: e.name || e.id })))
const publicUrl = computed(() => ev.value.public_url || '')
const isFull = computed(() => ev.value.capacity > 0 && headcount.value >= ev.value.capacity)
const capacityLabel = computed(() => ev.value.capacity ? `${headcount.value} / ${ev.value.capacity}` : headcount.value)

const filterState = ref({ search: '', chips: {} })
const chipGroups = [{ key: 'statut', label: 'Compte', icon: 'label', options: [{ value: 'confirmed', label: 'Confirmés', color: 'green-7' }, { value: 'probable', label: 'Probables', color: 'blue-6' }, { value: 'unverified', label: 'À vérifier', color: 'orange-7' }] }]

const columns = [
  { name: 'client', label: 'Client', field: 'customer_name', align: 'left', sortable: true },
  { name: 'party', label: 'Personnes', field: 'party_size', align: 'center', sortable: true },
  { name: 'email', label: 'Courriel', field: 'email', align: 'left' },
  { name: 'allergies', label: 'Allergies', field: 'allergies', align: 'left' },
  { name: 'confidence', label: 'Compte', field: 'confidence', align: 'center', sortable: true },
  { name: 'updated', label: 'Répondu le', field: 'updated', align: 'left', sortable: true },
  { name: 'actions', label: '', field: 'key', align: 'center' },
]

const filtered = computed(() => {
  const st = filterState.value.chips.statut
  const q = (filterState.value.search || '').toLowerCase().trim()
  return rows.value.filter(r => {
    const conf = r.confidence || 'none'
    if (st === 'confirmed' && conf !== 'confirmed') return false
    if (st === 'probable' && conf !== 'probable') return false
    if (st === 'unverified' && conf !== 'none') return false
    if (q && !((r.customer_name || '') + ' ' + (r.customer_number || '') + ' ' + (r.email || '') + ' ' + (r.phone || '')).toLowerCase().includes(q)) return false
    return true
  })
})

async function loadEventList (preferId) {
  try {
    const d = await listEvents()
    events.value = d.events || []
    if (!events.value.length) { eventId.value = ''; return }
    if (preferId && events.value.some(e => e.id === preferId)) eventId.value = preferId
    else if (!eventId.value || !events.value.some(e => e.id === eventId.value)) {
      const active = events.value.find(e => e.active) || events.value[0]
      eventId.value = active.id
    }
  } catch (e) { /* laisse load() rapporter l'erreur */ }
}

async function load () {
  if (!events.value.length) await loadEventList()
  if (!eventId.value) { loading.value = false; return }
  loading.value = true; error.value = ''
  try {
    const d = await listRsvps(eventId.value)
    ev.value = d.event || {}
    attachments.value = (d.event && d.event.attachments) || []
    rows.value = d.responses || []
    count.value = d.count || 0
    headcount.value = d.headcount || 0
    matched.value = d.matched || 0
    unmatched.value = d.unmatched || 0
  } catch (e) {
    error.value = 'Impossible de charger les inscriptions (' + e.message + '). La fonctionnalité doit être déployée sur le hub.'
  } finally { loading.value = false }
}

function onSelectEvent () { load() }

function copy (txt) {
  if (!txt) return
  navigator.clipboard?.writeText(txt).then(() => $q.notify({ type: 'positive', message: 'Lien copié', timeout: 1200 }))
    .catch(() => $q.notify({ type: 'warning', message: txt }))
}

function exportRows () {
  const conf = { confirmed: 'Confirmé', probable: 'Probable' }
  const headers = ['Client', 'N° client', 'ID compte', 'Nom au dossier', 'Téléphone', 'Personnes', 'Courriel', 'Allergies', 'Confiance', 'Signaux', 'Langue', 'IP', 'Créé le', 'Répondu le']
  const data = filtered.value.map(r => [r.customer_name || '', r.customer_number || '', r.customer_id || '', r.account_name || '', r.phone || '', r.party_size || 0, r.email || '', r.allergies || '', conf[r.confidence] || 'À vérifier', (r.signals || []).join(' + '), r.lang || '', r.ip || '', fmtDate(r.created), fmtDate(r.updated)])
  const totalRow = ['TOTAL', '', '', '', '', filtered.value.reduce((s, r) => s + (r.party_size || 0), 0), '', '', '', '', '', '', '', '']
  exportCsv(`inscriptions_${eventId.value}`, headers, data, { totalRow })
}

function confirmDelete (row) {
  $q.dialog({ title: 'Retirer l\'inscription', message: `Retirer ${row.customer_name || row.customer_number || 'cette inscription'} (${row.party_size} pers.) ?`, cancel: true, persistent: true })
    .onOk(async () => {
      try { await deleteRsvp(eventId.value, row.key); $q.notify({ type: 'positive', message: 'Retiré' }); load() }
      catch (e) { $q.notify({ type: 'negative', message: e.message }) }
    })
}

// ── Création / édition d'un événement ──────────────────────────────────────
const showForm = ref(false)
const formMode = ref('create')
const formLang = ref('fr')
const savingForm = ref(false)
const attFile = ref(null)
const attLang = ref('both')
const uploadingAtt = ref(false)
function attLangLabel (l) { return l === 'fr' ? 'FR' : l === 'en' ? 'EN' : 'Les deux' }
function attLangColor (l) { return l === 'fr' ? 'blue-7' : l === 'en' ? 'deep-orange-7' : 'grey-6' }

const emptyLang = () => ({ name: '', tagline: '', when: '', address: '', body: '', program: [], program_line: '', limited: '', closing: '', notes: [] })
const emptyForm = () => ({ id: '', active: true, date_iso: '', badge_top: '', badge_bottom: '', capacity: 0, email_template: '', fr: emptyLang(), en: emptyLang() })
const form = ref(emptyForm())

// Options du sélecteur de modèle : festif intégré + templates éditables (/campaigns/templates)
const emailTemplateOptions = computed(() => {
  const opts = templates.value.map(t => ({ value: t.value, label: t.value === '' ? 'Modèle festif intégré (TARGO)' : t.label }))
  if (!opts.some(o => o.value === '')) opts.unshift({ value: '', label: 'Modèle festif intégré (TARGO)' })
  return opts
})
// Aperçu de l'invitation
const invitePreviewOpen = ref(false)
const invitePreviewLang = ref('fr')
const invitePreviewHtml = ref('')
const previewLoading = ref(false)

function openCreate () {
  form.value = emptyForm()
  formMode.value = 'create'
  formLang.value = 'fr'
  if (templates.value.length <= 1) loadTemplates()
  showForm.value = true
}
async function openEdit () {
  if (!eventId.value) return
  try {
    const d = await getEventConfig(eventId.value)
    const c = d.event || {}
    const f = emptyForm()
    f.id = c.id || eventId.value
    f.active = c.active !== false
    f.date_iso = c.date_iso || ''
    f.badge_top = c.badge_top || ''
    f.badge_bottom = c.badge_bottom || ''
    f.capacity = c.capacity || 0
    f.email_template = c.email_template || ''
    for (const lg of ['fr', 'en']) {
      const src = c[lg] || {}
      f[lg] = {
        name: src.name || '', tagline: src.tagline || '', when: src.when || '', address: src.address || '', body: src.body || '',
        program: Array.isArray(src.program) ? src.program.map(p => ({ icon: p.icon || '', label: p.label || '', sub: p.sub || '' })) : [],
        program_line: src.program_line || '', limited: src.limited || '', closing: src.closing || '',
        notes: Array.isArray(src.notes) ? [...src.notes] : [],
      }
    }
    form.value = f
    formMode.value = 'edit'
    formLang.value = 'fr'
    if (templates.value.length <= 1) loadTemplates()
    showForm.value = true
  } catch (e) { $q.notify({ type: 'negative', message: e.message }) }
}
async function loadInvitePreview () {
  previewLoading.value = true
  try {
    const r = await getInvitePreview(form.value.id, { lang: invitePreviewLang.value, template: form.value.email_template })
    invitePreviewHtml.value = r.html || ''
  } catch (e) { $q.notify({ type: 'negative', message: 'Aperçu impossible : ' + e.message }); invitePreviewHtml.value = '' } finally { previewLoading.value = false }
}
async function openInvitePreview () { invitePreviewOpen.value = true; await loadInvitePreview() }

function cleanLang (c) {
  return {
    name: (c.name || '').trim(), tagline: (c.tagline || '').trim(), when: (c.when || '').trim(), address: (c.address || '').trim(), body: (c.body || '').trim(),
    program: (c.program || []).filter(p => (p.label || '').trim() || (p.icon || '').trim()),
    program_line: (c.program_line || '').trim(), limited: (c.limited || '').trim(), closing: (c.closing || '').trim(),
    notes: (c.notes || []).map(n => (n || '').trim()).filter(Boolean),
  }
}
async function saveForm () {
  if (!form.value.fr.name.trim()) { $q.notify({ type: 'warning', message: 'Le nom (français) est requis' }); formLang.value = 'fr'; return }
  savingForm.value = true
  try {
    const enHasContent = Object.values(form.value.en).some(v => Array.isArray(v) ? v.length : String(v || '').trim())
    const body = {
      active: form.value.active,
      date_iso: form.value.date_iso,
      badge_top: form.value.badge_top,
      badge_bottom: form.value.badge_bottom,
      capacity: form.value.capacity,
      email_template: form.value.email_template || '',
      fr: cleanLang(form.value.fr),
      ...(enHasContent ? { en: cleanLang(form.value.en) } : {}),
    }
    if (formMode.value === 'create') {
      const r = await createEvent(body)
      $q.notify({ type: 'positive', message: 'Événement créé' })
      showForm.value = false
      await loadEventList(r.event && r.event.id)
      await load()
    } else {
      await updateEvent(form.value.id, body)
      $q.notify({ type: 'positive', message: 'Événement enregistré' })
      showForm.value = false
      await loadEventList(form.value.id)
      await load()
    }
  } catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { savingForm.value = false }
}
function confirmDeleteEvent () {
  const seeded = form.value.id === 'fete-20-ans'
  $q.dialog({
    title: 'Supprimer l\'événement',
    message: seeded ? 'Réinitialiser cet événement à sa configuration par défaut ? Les inscriptions sont conservées.' : `Supprimer « ${form.value.fr.name} » ? Les inscriptions déjà reçues sont conservées.`,
    cancel: true, persistent: true, ok: { color: 'negative', label: seeded ? 'Réinitialiser' : 'Supprimer' },
  }).onOk(async () => {
    try {
      await deleteEvent(form.value.id)
      $q.notify({ type: 'positive', message: seeded ? 'Réinitialisé' : 'Supprimé' })
      showForm.value = false
      eventId.value = ''
      events.value = []
      await loadEventList()
      await load()
    } catch (e) { $q.notify({ type: 'negative', message: e.message }) }
  })
}

// ── Pièces jointes (édition) ───────────────────────────────────────────────
function onAttFile (file) {
  if (!file) return
  if (file.size > 4 * 1024 * 1024) { $q.notify({ type: 'warning', message: 'Fichier trop volumineux (max 4 Mo)' }); attFile.value = null; return }
  uploadingAtt.value = true
  const rd = new FileReader()
  rd.onload = async () => {
    try {
      const data = String(rd.result || '').replace(/^data:[^,]*,/, '')
      const r = await uploadAttachment(form.value.id, { filename: file.name, mime: file.type || 'application/octet-stream', data, lang: attLang.value })
      attachments.value = r.attachments || []
      const added = r.attachment
      $q.notify({ type: 'positive', message: `Pièce jointe ajoutée (${attLangLabel(added ? added.lang : attLang.value)})` })
    } catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { uploadingAtt.value = false; attFile.value = null }
  }
  rd.onerror = () => { uploadingAtt.value = false; attFile.value = null; $q.notify({ type: 'negative', message: 'Lecture du fichier impossible' }) }
  rd.readAsDataURL(file)
}
async function removeAtt (a) {
  try { const r = await deleteAttachment(form.value.id, a.stored); attachments.value = r.attachments || []; $q.notify({ type: 'positive', message: 'Retirée' }) }
  catch (e) { $q.notify({ type: 'negative', message: e.message }) }
}

// ── Envoi (test + aperçu audience) ─────────────────────────────────────────
function prepSend () { testEmail.value = testEmail.value || userEmail.value || ''; if (templates.value.length <= 1) loadTemplates(); loadMainList(); showSend.value = true }
async function loadTemplates () {
  try {
    const d = await listTemplates()
    const files = (d.templates || []).map(t => (typeof t === 'string' ? { value: t, label: t } : { value: t.name, label: t.label || t.name }))
    templates.value = [{ value: '', label: 'Invitation Fête 20 ans (TARGO)' }, ...files]
  } catch (e) { /* garde le défaut */ }
}
function onCsvFile (file) {
  if (!file) { audCsvText.value = ''; return }
  const rd = new FileReader()
  rd.onload = () => { audCsvText.value = String(rd.result || '') }
  rd.readAsText(file)
}
function onActiveSubToggle (v) { if (!v) audFilters.value.min_monthly = 0 } // le montant n'a de sens qu'avec les abonnements actifs

// ── Pool manuel : recherche floue temps réel → résultats en liste → sélection ──
function onPoolSearch (val) {
  const q = (val || '').trim()
  if (q.length < 2) { poolResults.value = []; return }
  poolSearching.value = true
  // Recherche FLOUE app-wide (pg_trgm, tolère typos + accents : « repa » trouve « Réparation »).
  searchCustomersFuzzy(q)
    .then(d => {
      poolResults.value = (d.matches || [])
        .filter(m => m.name && m.kind !== 'équipe') // clients seulement
        .map(m => ({ customer_id: m.name, customer_name: m.customer_name || m.name, email: (m.email || '').split(/[;,]/)[0].trim(), language: m.language || '', matched: m.matched || '' }))
    })
    .catch(() => { poolResults.value = [] })
    .finally(() => { poolSearching.value = false })
}
function inPool (m) { return pool.value.some(p => p.customer_id === m.customer_id) }
function addToPool (sel) {
  if (sel && sel.customer_id && !pool.value.some(p => p.customer_id === sel.customer_id)) pool.value.push(sel)
}
function removeFromPool (p) { pool.value = pool.value.filter(x => x.customer_id !== p.customer_id) }

// ── Liste principale : chargement + ajout de lots + retrait/vidage ─────────
async function loadMainList () {
  try { mainList.value = await getAudienceList(eventId.value) } catch (e) { /* liste vide si indispo */ }
}
function applyListResult (r, verb) {
  mainList.value = { count: r.count, by_source: r.by_source, sample: r.sample, updated: r.updated }
  const bits = []
  if (typeof r.added === 'number') bits.push(`${r.added} ajouté(s)`)
  if (r.duplicates) bits.push(`${r.duplicates} doublon(s) ignoré(s)`)
  if (r.dropped_no_email) bits.push(`${r.dropped_no_email} sans courriel`)
  if (r.resiliated_excluded) bits.push(`${r.resiliated_excluded} résilié(s) exclus`)
  $q.notify({ type: r.added === 0 && verb === 'add' ? 'warning' : 'positive', message: (bits.join(' · ') || verb) + ` — ${r.count} au total`, icon: 'playlist_add_check' })
}
function filterLabel () {
  const f = audFilters.value; const p = []
  if (f.city) p.push('Ville: ' + f.city)
  if (f.customer_type === 'Individual') p.push('Résidentiel'); else if (f.customer_type === 'Company') p.push('Commercial')
  if (f.name_like) p.push('Nom~' + f.name_like)
  if (f.active_sub) p.push(f.min_monthly > 0 ? `Abo ≥${f.min_monthly}$` : 'Abo actif')
  if (f.statut === 'active' && !p.length) p.push('Clients actifs')
  else if (f.statut !== 'active') p.push('incl. résiliés')
  return p.join(' · ') || 'Filtre'
}
async function addFilterToList () {
  listBusy.value = true
  // « Tous » (statut vide) autorise les ex-clients résiliés ; « Clients actifs » les exclut.
  const filters = { ...audFilters.value, include_resiliated: audFilters.value.statut !== 'active' }
  try { applyListResult(await audienceListAdd(eventId.value, { mode: 'filter', filters, source_label: filterLabel() }), 'add') }
  catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { listBusy.value = false }
}
async function addManualToList () {
  if (!pool.value.length) return
  listBusy.value = true
  try {
    const r = await audienceListAdd(eventId.value, { mode: 'manual', filters: { customer_ids: pool.value.map(p => p.customer_id) }, source_label: 'Sélection manuelle' })
    applyListResult(r, 'add'); pool.value = []
  } catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { listBusy.value = false }
}
async function addCsvToList () {
  if (!audCsvText.value) return
  listBusy.value = true
  try {
    const r = await audienceListAdd(eventId.value, { mode: 'csv', csv: audCsvText.value, source_label: 'CSV' + (csvFile.value ? ': ' + csvFile.value.name : '') })
    applyListResult(r, 'add'); csvFile.value = null; audCsvText.value = ''
  } catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { listBusy.value = false }
}
async function removeFromList (r) {
  listBusy.value = true
  try { const res = await audienceListRemove(eventId.value, r.email); mainList.value = { count: res.count, by_source: res.by_source, sample: res.sample, updated: res.updated } }
  catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { listBusy.value = false }
}
function clearList () {
  $q.dialog({ title: 'Vider la liste', message: 'Retirer tous les destinataires de la liste d\'envoi ?', cancel: true, persistent: true, ok: { color: 'negative', label: 'Vider' } })
    .onOk(async () => {
      listBusy.value = true
      try { const r = await audienceListClear(eventId.value); mainList.value = { count: 0, by_source: {}, sample: [], updated: '' }; void r; $q.notify({ type: 'positive', message: 'Liste vidée' }) }
      catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { listBusy.value = false }
    })
}
function goCampaigns () { window.location.hash = '#/campaigns' }
const sendingMass = ref(false)
function confirmMassSend () {
  const n = mainList.value.count
  if (!n) return
  const chan = sendChannel.value === 'gmail' ? 'Gmail' : 'Mailjet'
  $q.dialog({
    title: "Envoyer l'invitation",
    message: `Envoyer un vrai courriel d'invitation à <b>${n}</b> destinataire(s) via <b>${chan}</b> ?<br>Chacun reçoit un lien RSVP personnel. Cette action est irréversible.`,
    html: true,
    cancel: { label: 'Annuler', flat: true, noCaps: true },
    ok: { label: `Envoyer à ${n}`, color: 'negative', unelevated: true, noCaps: true },
    persistent: true,
  }).onOk(async () => {
    sendingMass.value = true
    try {
      const r = await sendInvite(eventId.value, { mass: true, channel: sendChannel.value })
      $q.notify({ type: 'positive', message: `Envoi lancé à ${r.count} destinataire(s)`, caption: 'Suivi dans Campagnes', icon: 'send', timeout: 7000, actions: [{ label: 'Ouvrir Campagnes', color: 'white', handler: goCampaigns }] })
      showSend.value = false
      load()
    } catch (e) { $q.notify({ type: 'negative', message: 'Échec du lancement : ' + e.message }) } finally { sendingMass.value = false }
  })
}
async function sendTestNow () {
  const em = (testEmail.value || '').trim()
  if (!em) { $q.notify({ type: 'warning', message: 'Entrez un courriel de test' }); return }
  sending.value = true
  try {
    const r = await sendInvite(eventId.value, { test: true, test_emails: [em], channel: sendChannel.value, lang: testLang.value })
    if (r.ok) $q.notify({ type: 'positive', message: `Courriel test envoyé à ${em}`, icon: 'send' })
    else $q.notify({ type: 'negative', message: 'Échec : ' + ((r.results && r.results[0] && r.results[0].error) || 'inconnu') })
  } catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { sending.value = false }
}

onMounted(load)
</script>

<style scoped>
.ev-badge { display:flex; flex-direction:column; align-items:center; justify-content:center; width:52px; height:52px; border-radius:50%; background:#21a34a; color:#fff; font-weight:800; line-height:1; flex:0 0 auto; }
.ev-badge b { font-size:1.15rem; }
.ev-badge span { font-size:.52rem; letter-spacing:1px; }
</style>
