/* Admin flow v2 — login + dashboard + respondents list + detail + invitations */

const { useState: useStateB, useMemo: useMemoB } = React;

const PALETTE = [
  "var(--byi-navy-800)",
  "var(--byi-orange-500)",
  "var(--byi-cyan-500)",
  "var(--byi-teal-500)",
  "var(--byi-coral-500)",
  "var(--byi-yellow-500)",
  "var(--byi-purple-500)",
  "var(--byi-navy-600)"
];

/* ============================================================
   Aggregation specific to v2 schema
   ============================================================ */
function aggV2(respondents) {
  const count = (arr, key) => {
    const m = new Map();
    arr.forEach(r => {
      const v = r[key];
      if (Array.isArray(v)) v.forEach(x => m.set(x, (m.get(x) || 0) + 1));
      else if (v != null && v !== "") m.set(v, (m.get(v) || 0) + 1);
    });
    return [...m.entries()].map(([label, value]) => ({ label, value })).sort((a, b) => b.value - a.value);
  };

  const users = respondents.filter(r => r.isUser);

  const skillHist = Array.from({ length: 10 }, (_, i) => ({
    label: String(i + 1),
    value: respondents.filter(r => r.skill === i + 1).length
  }));
  const avgSkill = respondents.reduce((s, r) => s + r.skill, 0) / Math.max(respondents.length, 1);

  const dayCounts = Array.from({ length: 21 }, () => 0);
  respondents.forEach(r => {
    const days = Math.floor((new Date(2026, 4, 23) - r.submittedAt) / (1000 * 60 * 60 * 24));
    const idx = 20 - Math.max(0, Math.min(20, days));
    dayCounts[idx] += 1;
  });

  // Themes — simple multi-select count
  const themesWeighted = (() => {
    const m = new Map();
    respondents.forEach(r => (r.themes || []).forEach(t => m.set(t, (m.get(t) || 0) + 1)));
    return [...m.entries()].map(([label, value]) => ({ label, value })).sort((a, b) => b.value - a.value);
  })();

  // Headcount per service totals + modules x service matrix
  const services = new Map();
  const moduleServiceMatrix = new Map(); // service -> Map(module -> count)
  respondents.forEach(r => {
    if (!r.trainingPlan) return;
    Object.entries(r.trainingPlan).forEach(([s, plan]) => {
      services.set(s, (services.get(s) || 0) + (Number(plan.headcount) || 0));
      if (!moduleServiceMatrix.has(s)) moduleServiceMatrix.set(s, new Map());
      (plan.themes || []).forEach(m => {
        const ms = moduleServiceMatrix.get(s);
        ms.set(m, (ms.get(m) || 0) + 1);
      });
    });
  });
  const headcountByService = [...services.entries()]
    .map(([label, value]) => ({ label, value }))
    .sort((a, b) => b.value - a.value);
  const modulesByService = [...moduleServiceMatrix.entries()]
    .map(([service, ms]) => ({
      service,
      modules: [...ms.entries()].map(([label, value]) => ({ label, value })).sort((a, b) => b.value - a.value)
    }));
  // People-to-train per module: sum headcount of every (respondent × service) where the module is selected
  const moduleTrainees = (() => {
    const m = new Map();
    respondents.forEach(r => {
      if (!r.trainingPlan) return;
      Object.values(r.trainingPlan).forEach(plan => {
        const h = Number(plan.headcount) || 0;
        if (h <= 0) return;
        (plan.themes || []).forEach(t => m.set(t, (m.get(t) || 0) + h));
      });
    });
    return [...m.entries()].map(([label, value]) => ({ label, value })).sort((a, b) => b.value - a.value);
  })();

  // Tool counts grouped by category
  const toolsByGroup = window.FESPA_DATA.catalog.TOOLS_GROUPS.map(g => ({
    group: g.group,
    items: g.tools.map(t => ({
      label: t,
      value: users.filter(r => r.tools.includes(t)).length
    })).sort((a, b) => b.value - a.value)
  }));

  // Licences: number of orgs with each tool + total licences
  const licCount = new Map();
  const licSeats = new Map();
  respondents.forEach(r => {
    (r.licences || []).forEach(l => {
      licCount.set(l.tool, (licCount.get(l.tool) || 0) + 1);
      licSeats.set(l.tool, (licSeats.get(l.tool) || 0) + l.count);
    });
  });
  const licencesData = [...licCount.entries()].map(([tool, orgs]) => ({
    label: tool, orgs, seats: licSeats.get(tool) || 0
  })).sort((a, b) => b.seats - a.seats);

  return {
    roles: count(respondents, "role"),
    sizes: count(respondents, "sizeLabel"),
    sectors: count(respondents, "sectors"),
    opcoSalaries: count(respondents, "opcoSalaries"),
    opcoDirigeant: count(respondents, "opcoDirigeant"),
    usage: count(respondents, "usage"),
    domains: count(users, "domains"),
    benefits: count(users, "benefits"),
    policy: count(respondents, "policy"),
    barriers: count(respondents, "barriers"),
    paidStatus: count(respondents.filter(r => r.isUser), "paidStatus"),
    wantsFormation: count(respondents, "wantsFormation"),
    budget: count(respondents.filter(r => r.wantsFormation !== "Non, pas pour l'instant"), "budgetLabel"),
    decider: count(respondents.filter(r => r.wantsFormation !== "Non, pas pour l'instant"), "decider"),
    pastTrained: respondents.filter(r => r.pastTraining).length,
    skillHist, avgSkill, dayCounts,
    themesWeighted,
    headcountByService,
    modulesByService,
    moduleTrainees,
    toolsByGroup,
    licencesData
  };
}

/* ============================================================
   CSV export
   ============================================================ */
function exportRespondentsCSV(respondents, catalog) {
  const headers = [
    "ID", "Soumis le", "Prénom", "Nom", "Email", "Entreprise", "Rôle",
    "Effectif (tranche)", "Secteurs", "OPCO salariés", "OPCO dirigeant",
    "Niveau IA (/10)", "Usage IA",
    "Outils utilisés", "Statut licences payantes", "Outils sous licence (sièges)",
    "Domaines d'usage", "Bénéfices observés",
    "Politique IA", "Freins identifiés",
    "Formation IA déjà suivie", "Détails formation antérieure",
    "Intérêt formation", "Plan par service (apprenants × modules)",
    "Total apprenants", "Budget / personne", "Décideur formation",
    "Atelier témoignage", "Commentaire libre"
  ];

  const escape = (v) => {
    if (v == null) return "";
    const s = String(v);
    if (s.includes('"') || s.includes(";") || s.includes("\n") || s.includes(",")) {
      return '"' + s.replace(/"/g, '""') + '"';
    }
    return s;
  };

  const fmtDate = (d) => {
    const dt = d instanceof Date ? d : new Date(d);
    return `${String(dt.getDate()).padStart(2,"0")}/${String(dt.getMonth()+1).padStart(2,"0")}/${dt.getFullYear()} ${String(dt.getHours()).padStart(2,"0")}:${String(dt.getMinutes()).padStart(2,"0")}`;
  };

  const rows = respondents.map(r => {
    const licStr = (r.licences || []).map(l => `${l.tool} (${l.count})`).join(" | ");
    const planStr = r.trainingPlan
      ? Object.entries(r.trainingPlan)
          .filter(([, p]) => Number(p.headcount) > 0 || (p.themes||[]).length > 0)
          .map(([s, p]) => `${s}: ${p.headcount} apprenant(s)${p.themes && p.themes.length ? " — " + p.themes.join(", ") : ""}`)
          .join(" | ")
      : "";
    const pastStr = r.pastTraining
      ? `${r.pastTraining.title} (${r.pastTraining.organism}, ${r.pastTraining.year}, ${r.pastTraining.headcount} pers.)`
      : "";

    return [
      r.id,
      fmtDate(r.submittedAt),
      r.firstName,
      r.lastName,
      r.email,
      r.company,
      r.role,
      r.sizeLabel,
      (r.sectors || []).join(" | "),
      (r.opcoSalaries || []).join(" | "),
      (r.opcoDirigeant || []).join(" | "),
      r.skill,
      r.usage,
      (r.tools || []).join(" | "),
      r.paidStatus || "",
      licStr,
      (r.domains || []).join(" | "),
      (r.benefits || []).join(" | "),
      r.policy || "",
      (r.barriers || []).join(" | "),
      r.pastTraining ? "Oui" : "Non",
      pastStr,
      r.wantsFormation || "",
      planStr,
      r.trainTotal || 0,
      r.budgetLabel || "",
      r.decider || "",
      r.willingToShare || "",
      r.comment || ""
    ];
  });

  const sep = ";"; // semicolon: Excel FR friendly
  const lines = [headers.join(sep), ...rows.map(r => r.map(escape).join(sep))];
  const csv = "\uFEFF" + lines.join("\r\n"); // BOM for Excel UTF-8

  const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  const today = new Date();
  const stamp = `${today.getFullYear()}${String(today.getMonth()+1).padStart(2,"0")}${String(today.getDate()).padStart(2,"0")}`;
  a.href = url;
  a.download = `FESPA-enquete-IA-${stamp}.csv`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

window.exportRespondentsCSV = exportRespondentsCSV;

/* ============================================================
   Login
   ============================================================ */
function AdminLogin({ onLogin }) {
  const [email, setEmail] = useStateB("admin@fespa-france.fr");
  const [pw, setPw] = useStateB("••••••••");
  const [showHint, setShowHint] = useStateB(false);
  return (
    <div className="ad-login">
      <div className="ad-login__panel">
        <div className="ad-login__brand">
          <FespaMark variant="dark" size={1.1} />
          <Eyebrow>Espace administrateur · accès sécurisé</Eyebrow>
        </div>
        <h1 className="byi-h2 ad-login__title">Suivi de l'enquête<br/>Usage de l'IA — 2026</h1>
        <form className="ad-login__form" onSubmit={e => { e.preventDefault(); onLogin(); }}>
          <label className="qf-input">
            <span>Identifiant FESPA France</span>
            <input value={email} onChange={e => setEmail(e.target.value)} />
          </label>
          <label className="qf-input">
            <span>Mot de passe</span>
            <input type="password" value={pw} onChange={e => setPw(e.target.value)} />
          </label>
          <label className="ad-login__check">
            <input type="checkbox" defaultChecked /> Garder ma session active sur ce poste
          </label>
          <Button size="lg" type="submit">Se connecter →</Button>
          <button className="ad-login__hint" type="button" onClick={() => setShowHint(s => !s)}>
            Identifiants oubliés ?
          </button>
          {showHint && (
            <div className="ad-login__hintbox">
              Un seul couple identifiant / mot de passe par compte FESPA France.
              Contactez le secrétariat pour une réinitialisation.
            </div>
          )}
        </form>
      </div>
      <aside className="ad-login__side">
        <Eyebrow color="var(--byi-orange-400)">Commission Intelligence Artificielle</Eyebrow>
        <h2 className="byi-h3 ad-login__side-title">
          Une lecture en temps réel<br/>du pouls de la filière.
        </h2>
        <ul className="ad-login__bullets">
          <li>Volume de réponses & couverture OPCO</li>
          <li>Outils utilisés et licences payantes en place</li>
          <li>Intentions de formation par service et par budget</li>
          <li>Export CSV pour vos comités</li>
        </ul>
        <div className="ad-login__shape"></div>
      </aside>
    </div>
  );
}

/* ============================================================
   Campaigns — Several surveys per year, each with its own questionnaire
   ============================================================ */
const FESPA_CAMPAIGNS = [
  {
    id: "ia-2026",
    name: "Usage de l'IA — Édition 2026",
    period: "Mai → Juin 2026",
    startDate: "2026-05-05",
    endDate: "2026-06-12",
    status: "open",
    invited: 416,
    responded: 80,
    questionnaireId: "ia-v2",
    questionsCount: 20,
    blocks: 5,
    description: "Cartographier l'adoption de l'IA et identifier les besoins en formation des adhérents.",
    isPrimary: true
  },
  {
    id: "conjoncture-q1-2026",
    name: "Conjoncture filière — T1 2026",
    period: "Mars → Avril 2026",
    startDate: "2026-03-01",
    endDate: "2026-04-15",
    status: "closed",
    invited: 416,
    responded: 248,
    questionnaireId: "conjoncture",
    questionsCount: 12,
    blocks: 3,
    description: "Baromètre trimestriel : carnet de commandes, prix matières, recrutement."
  },
  {
    id: "salon-2025",
    name: "Bilan Salon FESPA Global 2025",
    period: "Octobre 2025",
    startDate: "2025-10-15",
    endDate: "2025-11-15",
    status: "closed",
    invited: 198,
    responded: 142,
    questionnaireId: "salon-bilan",
    questionsCount: 15,
    blocks: 4,
    description: "Bilan post-salon — satisfaction exposants, contacts générés, intentions 2026."
  },
  {
    id: "formation-2027",
    name: "Plan de formation 2027 — Exploration",
    period: "Septembre → Octobre 2026 (prévue)",
    startDate: "2026-09-01",
    endDate: "2026-10-31",
    status: "draft",
    invited: 0,
    responded: 0,
    questionnaireId: "formation-2027",
    questionsCount: 8,
    blocks: 2,
    description: "Questionnaire en cours de rédaction — orientations pour le plan 2027."
  }
];

window.FESPA_CAMPAIGNS = FESPA_CAMPAIGNS;
const ADMIN_AREAS = [
  { id: "survey",    label: "Suivi de l'enquête",          icon: "📊",
    tabs: [
      ["campaigns",   "Campagnes"],
      ["dashboard",   "Vue d'ensemble"],
      ["respondents", "Répondants"],
      ["invitations", "Invitations"]
    ] },
  { id: "training",  label: "Inscriptions aux formations", icon: "🎓",
    tabs: [
      ["sessions",     "Sessions"],
      ["enrollments",  "Inscrits"],
      ["catalog",      "Catalogue"]
    ] },
  { id: "planning",  label: "Rétro-planning",               icon: "🗓",
    tabs: [
      ["gantt",      "Vue planning"],
      ["milestones", "Jalons clés"]
    ] }
];

function AdminShell({ area, tab, onArea, onTab, onLogout, campaignId, onCampaignChange, children }) {
  const current = ADMIN_AREAS.find(a => a.id === area) || ADMIN_AREAS[0];
  const currentCampaign = FESPA_CAMPAIGNS.find(c => c.id === campaignId) || FESPA_CAMPAIGNS[0];
  const showSwitcher = area === "survey" && tab !== "campaigns";
  return (
    <div className="adm">
      <header className="adm__top">
        <div className="adm__brand">
          <FespaMark variant="dark" size={0.95} />
          <span className="adm__brand-divider"></span>
          <span className="byi-eyebrow" style={{ color: "var(--fg-soft)" }}>Console administrateur</span>
        </div>
        <nav className="adm__areas">
          {ADMIN_AREAS.map(a => (
            <button
              key={a.id}
              className={`adm__area ${area === a.id ? "is-active" : ""}`}
              onClick={() => onArea(a.id)}
            >
              <span className="adm__area-icon">{a.icon}</span>
              <span>{a.label}</span>
            </button>
          ))}
        </nav>
        <div className="adm__user">
          <div className="adm__user-avatar">AF</div>
          <div className="adm__user-info">
            <strong>Anne F.</strong>
            <span>Direction · FESPA France</span>
          </div>
          <button className="adm__logout" onClick={onLogout} title="Se déconnecter">⎋</button>
        </div>
      </header>
      <div className="adm__subnav">
        <div className="adm__subnav-area">{current.label}</div>
        <nav className="adm__nav">
          {current.tabs.map(([id, label]) => (
            <button
              key={id}
              className={`adm__nav-item ${tab === id ? "is-active" : ""}`}
              onClick={() => onTab(id)}
            >{label}</button>
          ))}
        </nav>
        {showSwitcher && (
          <div className="adm__switcher">
            <span className="adm__switcher-lbl">Campagne&nbsp;:</span>
            <select className="adm__switcher-select"
              value={campaignId}
              onChange={e => onCampaignChange(e.target.value)}>
              {FESPA_CAMPAIGNS.map(c => (
                <option key={c.id} value={c.id}>
                  {c.name} {c.status === "open" ? "· en cours" : c.status === "closed" ? "· clôturée" : "· brouillon"}
                </option>
              ))}
            </select>
            <CampaignStatus status={currentCampaign.status}/>
          </div>
        )}
      </div>
      <main className="adm__main">{children}</main>
    </div>
  );
}

function CampaignStatus({ status }) {
  const map = {
    open: ["var(--success)", "Ouverte"],
    closed: ["var(--byi-navy-300)", "Clôturée"],
    draft: ["var(--byi-orange-500)", "Brouillon"],
    scheduled: ["var(--byi-cyan-500)", "Programmée"]
  };
  const [c, l] = map[status] || map.draft;
  return <span className="status-chip" style={{ "--c": c }}><span></span>{l}</span>;
}

function AdminCampaigns({ onSelectCampaign }) {
  const [showCreate, setShowCreate] = useStateB(false);
  return (
    <div className="dash">
      <div className="dash__head">
        <div>
          <Eyebrow>Toutes les campagnes</Eyebrow>
          <h1 className="byi-h2 dash__title" style={{whiteSpace:"nowrap"}}>{FESPA_CAMPAIGNS.length} enquêtes — édition annuelle</h1>
        </div>
        <div className="dash__head-actions">
          <Button variant="ghost" icon="⬇">Exporter le bilan</Button>
          <Button icon="＋" onClick={() => setShowCreate(true)}>Nouvelle campagne</Button>
        </div>
      </div>

      <div className="camp-grid">
        {FESPA_CAMPAIGNS.map(c => {
          const rate = c.invited > 0 ? Math.round(c.responded / c.invited * 100) : 0;
          return (
            <Card key={c.id} padding="lg" className={`camp ${c.isPrimary ? "camp--primary" : ""} camp--${c.status}`}>
              <div className="camp__head">
                <div>
                  <Eyebrow color={c.status === "open" ? "var(--byi-orange-500)" : "var(--fg-soft)"}>
                    {c.period}
                  </Eyebrow>
                  <h3 className="camp__title">{c.name}</h3>
                </div>
                <CampaignStatus status={c.status}/>
              </div>

              <p className="camp__desc">{c.description}</p>

              <div className="camp__meta">
                <div>
                  <span>Questions</span>
                  <strong>{c.questionsCount}</strong>
                </div>
                <div>
                  <span>Blocs</span>
                  <strong>{c.blocks}</strong>
                </div>
                <div>
                  <span>Invitations</span>
                  <strong>{c.invited > 0 ? c.invited : "—"}</strong>
                </div>
                <div>
                  <span>Réponses</span>
                  <strong>{c.responded > 0 ? c.responded : "—"}</strong>
                </div>
              </div>

              {c.invited > 0 && (
                <div className="camp__progress">
                  <div className="camp__progress-head">
                    <span>Taux de réponse</span>
                    <strong>{rate}%</strong>
                  </div>
                  <div className="camp__progress-bar">
                    <div className="camp__progress-fill"
                      style={{
                        width: `${rate}%`,
                        background: c.status === "open" ? "var(--accent)" : "var(--byi-navy-600)"
                      }}></div>
                  </div>
                </div>
              )}

              <div className="camp__actions">
                {c.status === "draft" ? (
                  <Button size="sm">✎ Éditer le questionnaire</Button>
                ) : (
                  <Button size="sm" onClick={() => onSelectCampaign(c.id)}>
                    📊 Voir les résultats →
                  </Button>
                )}
                <button className="camp__menu-btn" title="Plus d'actions">⋯</button>
              </div>
            </Card>
          );
        })}
      </div>

      {/* Create campaign modal */}
      {showCreate && (
        <div className="adm-modal" onClick={() => setShowCreate(false)}>
          <div className="adm-modal__panel" onClick={e => e.stopPropagation()}>
            <div className="adm-modal__head">
              <div>
                <Eyebrow>Nouvelle campagne</Eyebrow>
                <h2 className="byi-h3 adm-modal__title">Créer une nouvelle enquête</h2>
              </div>
              <button type="button" className="adm-modal__close" onClick={() => setShowCreate(false)}>×</button>
            </div>

            <p className="adm-modal__help">
              Une campagne correspond à <strong>une enquête</strong> diffusée auprès des adhérents.
              Chaque campagne a son propre questionnaire, sa propre liste d'invités et son propre tableau de résultats.
            </p>

            <div className="adm-modal__body">
              <label className="qf-input qf-input--full">
                <span>Nom de la campagne <span style={{color:"var(--danger)"}}>*</span></span>
                <input placeholder="Ex : Conjoncture filière — T2 2026" />
              </label>
              <div className="qf-grid-2">
                <label className="qf-input">
                  <span>Date d'ouverture</span>
                  <input type="date" />
                </label>
                <label className="qf-input">
                  <span>Date de clôture</span>
                  <input type="date" />
                </label>
              </div>
              <label className="qf-input qf-input--full">
                <span>Description (objectif de l'enquête)</span>
                <textarea className="qf-textarea" rows={3}
                  placeholder="Pourquoi cette enquête ? À qui s'adresse-t-elle ?"></textarea>
              </label>
              <label className="qf-input qf-input--full">
                <span>Partir d'un modèle</span>
                <select className="qf-select">
                  <option>Questionnaire vierge (commencer de zéro)</option>
                  <option>Dupliquer « Usage de l'IA — 2026 » (20 questions)</option>
                  <option>Dupliquer « Conjoncture filière — T1 2026 » (12 questions)</option>
                  <option>Modèle FESPA — Baromètre trimestriel</option>
                  <option>Modèle FESPA — Bilan salon</option>
                </select>
              </label>
            </div>

            <div className="adm-modal__footer">
              <Button variant="ghost" type="button" onClick={() => setShowCreate(false)}>Annuler</Button>
              <Button>＋ Créer la campagne</Button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function CampaignClosedNotice({ campaign }) {
  return (
    <Card padding="lg" className="campnotice">
      <div className="campnotice__icon">📋</div>
      <div>
        <Eyebrow>{campaign.period}</Eyebrow>
        <h2 className="byi-h3" style={{marginTop: 4}}>{campaign.name}</h2>
        <p className="byi-lede" style={{margin: "12px 0", fontSize: 15}}>{campaign.description}</p>
        <div className="campnotice__stats">
          <div><span>Statut</span><strong><CampaignStatus status={campaign.status}/></strong></div>
          <div><span>Questions</span><strong>{campaign.questionsCount}</strong></div>
          <div><span>Invitations</span><strong>{campaign.invited}</strong></div>
          <div><span>Réponses</span><strong>{campaign.responded}</strong> ({Math.round(campaign.responded/Math.max(campaign.invited,1)*100)}%)</div>
        </div>
        <p className="byi-caption" style={{marginTop: 16, lineHeight: 1.6}}>
          {campaign.status === "closed"
            ? "Cette campagne est clôturée. Les données restent consultables et exportables. Cliquez sur les onglets « Répondants » et « Invitations » pour explorer les détails."
            : campaign.status === "draft"
              ? "Cette campagne est en cours de préparation — le questionnaire n'a pas encore été diffusé aux adhérents."
              : "Campagne en cours."}
        </p>
      </div>
    </Card>
  );
}

/* ============================================================
   Dashboard
   ============================================================ */
function AdminDashboard({ data, onOpenRespondent }) {
  const totals = data.totals;
  const agg = useMemoB(() => aggV2(data.respondents), [data.respondents]);
  const users = data.respondents.filter(r => r.isUser);
  const wantsFormation = data.respondents.filter(r => r.wantsFormation !== "Non, pas pour l'instant");

  const satOrder = [
    ["Oui, une charte ou politique formalisée", "var(--success)"],
    ["Oui, des règles informelles", "var(--byi-teal-500)"],
    ["Non, mais c'est en réflexion", "var(--byi-orange-500)"],
    ["Non, pas du tout", "var(--byi-coral-500)"]
  ];

  return (
    <div className="dash">
      <div className="dash__head">
        <div>
          <Eyebrow>Vue d'ensemble · 23 mai 2026</Eyebrow>
          <h1 className="byi-h2 dash__title" style={{whiteSpace: "nowrap"}}>Enquête « Usage de l'IA » — résultats en direct</h1>
        </div>
        <div className="dash__head-actions">
          <Chip tone="success">● Enquête ouverte</Chip>
          <Button variant="ghost" icon="⬇" onClick={() => exportRespondentsCSV(data.respondents, data.catalog)}>Exporter CSV</Button>
          <Button variant="ghost" icon="📨">Relancer {totals.invited - totals.responded} non-répondants</Button>
        </div>
      </div>

      {/* ===== Row 1 — Top KPIs ===== */}
      <div className="dash__kpis">
        <Card padding="lg" className="kpi kpi--big">
          <div className="kpi__head">
            <Eyebrow>Taux de réponse</Eyebrow>
            <Chip tone="accent" size="sm">+9 cette semaine</Chip>
          </div>
          <div className="kpi__body">
            <DonutChart
              value={totals.responded} total={totals.invited} size={180}
              color="var(--byi-orange-500)"
              label={`${Math.round(totals.responseRate * 100)}%`}
              sublabel={`${totals.responded} / ${totals.invited}`}
            />
            <div className="kpi__notes">
              <p><strong>{totals.responded}</strong> questionnaires saisis sur <strong>{totals.invited}</strong> adhérents invités.</p>
              <p className="byi-caption">Objectif comité : 60 %. Estimé atteint sous 8 jours.</p>
            </div>
          </div>
        </Card>

        <Card padding="lg" className="kpi">
          <Eyebrow>Volume collaborateurs cumulé</Eyebrow>
          <div className="kpi__hero-num">{totals.collaborators.toLocaleString("fr-FR")}</div>
          <div className="byi-caption">salariés représentés au total</div>
          <div className="kpi__legend">
            {agg.sizes.map((s, i) => (
              <div className="kpi__legend-row" key={s.label}>
                <span className="kpi__legend-pill" style={{ background: PALETTE[i % PALETTE.length] }}></span>
                <span>{s.label}</span>
                <strong>{s.value}</strong>
              </div>
            ))}
          </div>
        </Card>

        <Card padding="lg" className="kpi">
          <Eyebrow>Niveau IA moyen</Eyebrow>
          <div className="kpi__hero-num">{agg.avgSkill.toFixed(1)}<span className="kpi__hero-suffix">/10</span></div>
          <div className="byi-caption">déclaré par les répondants</div>
          <VBar
            data={agg.skillHist.map(d => ({ ...d, highlight: Number(d.label) === Math.round(agg.avgSkill) }))}
            height={120}
            color="var(--byi-navy-100)"
            accent="var(--byi-orange-500)"
          />
        </Card>

        <Card padding="lg" className="kpi">
          <Eyebrow>Courbe des réponses · 21 jours</Eyebrow>
          <div className="kpi__hero-num">+{agg.dayCounts.slice(-7).reduce((s, v) => s + v, 0)}</div>
          <div className="byi-caption">réponses sur les 7 derniers jours</div>
          <Sparkline data={agg.dayCounts} width={300} height={90} color="var(--byi-orange-500)" />
          <div className="kpi__sparklabels">
            <span>il y a 21 j</span><span>aujourd'hui</span>
          </div>
        </Card>
      </div>

      {/* ===== Row 2 — Profil & OPCO ===== */}
      <div className="dash__row dash__row--2col">
        <Card padding="lg" className="dash__panel">
          <Eyebrow>Profil — rôle des répondants</Eyebrow>
          <HBar
            data={agg.roles.map((r, i) => ({ ...r, color: PALETTE[i % PALETTE.length] }))}
            height={22}
          />
        </Card>

        <Card padding="lg" className="dash__panel">
          <Eyebrow>Secteur d'activité</Eyebrow>
          <HBar
            data={agg.sectors.map((s, i) => ({ ...s, color: PALETTE[i % PALETTE.length] }))}
            height={22}
          />
        </Card>
      </div>

      <div className="dash__row dash__row--1col">
        <Card padding="lg" className="dash__panel">
          <div className="dash__panel-head">
            <div>
              <Eyebrow color="var(--byi-orange-500)">OPCO de rattachement</Eyebrow>
              <h3 className="byi-h4" style={{margin: "4px 0 0"}}>Couverture par OPCO</h3>
            </div>
          </div>
          <div className="dash__opco">
            <div className="dash__opco-col">
              <div className="dash__panel-sublabel">Pour les salariés</div>
              <HBar
                data={agg.opcoSalaries.map((o, i) => ({
                  ...o, color: i === 0 ? "var(--byi-orange-500)" : "var(--byi-navy-300)"
                }))}
                height={18}
              />
            </div>
            <div className="dash__opco-col">
              <div className="dash__panel-sublabel">Pour le dirigeant</div>
              <HBar
                data={agg.opcoDirigeant.map((o, i) => ({
                  ...o, color: i === 0 ? "var(--byi-orange-500)" : "var(--byi-navy-300)"
                }))}
                height={18}
              />
            </div>
          </div>
        </Card>
      </div>

      {/* ===== Row 3 — Adoption + Tools by category ===== */}
      <div className="dash__row dash__row--2col">
        <Card padding="lg" className="dash__panel">
          <div className="dash__panel-head">
            <div>
              <Eyebrow>Adoption de l'IA dans la filière</Eyebrow>
              <h3 className="byi-h4">Où en sont les entreprises adhérentes ?</h3>
            </div>
          </div>
          <HBar
            data={agg.usage.map((u) => ({
              ...u,
              color: ["Oui, régulièrement","Oui, occasionnellement","Nous sommes en phase de test"].includes(u.label)
                ? "var(--byi-orange-500)"
                : "var(--byi-navy-300)"
            }))}
            height={26}
          />
          <div className="dash__split">
            <div>
              <div className="dash__split-num">
                {Math.round(100 * users.length / data.respondents.length)}%
              </div>
              <div className="byi-caption">utilisent déjà l'IA</div>
            </div>
            <div>
              <div className="dash__split-num">
                {Math.round(100 * (agg.usage.find(u => u.label === "Nous sommes en phase de test") || {value:0}).value / data.respondents.length)}%
              </div>
              <div className="byi-caption">en phase de test</div>
            </div>
            <div>
              <div className="dash__split-num">
                {Math.round(100 * (agg.usage.find(u => u.label === "Non, mais nous y réfléchissons") || {value:0}).value / data.respondents.length)}%
              </div>
              <div className="byi-caption">en réflexion</div>
            </div>
          </div>
        </Card>

        <Card padding="lg" className="dash__panel">
          <div className="dash__panel-head">
            <div>
              <Eyebrow>Outils utilisés · par catégorie</Eyebrow>
              <h3 className="byi-h4">Top 3 par famille d'outils</h3>
            </div>
            <span className="byi-caption">{users.length} utilisateurs IA</span>
          </div>
          <div className="dash__tool-groups">
            {agg.toolsByGroup.map(g => (
              <div key={g.group} className="dash__tool-group">
                <div className="dash__tool-group-title">{g.group}</div>
                <HBar
                  data={g.items.slice(0, 3).filter(i => i.value > 0).map((t, i) => ({
                    ...t, color: i === 0 ? "var(--byi-navy-800)" : "var(--byi-navy-300)"
                  }))}
                  height={16}
                />
              </div>
            ))}
          </div>
        </Card>
      </div>

      {/* ===== Row 4 — Licences payantes ===== */}
      <Card padding="lg" className="dash__panel">
        <div className="dash__panel-head">
          <div>
            <Eyebrow color="var(--byi-cyan-500)">Licences payantes en place</Eyebrow>
            <h3 className="byi-h4">Quels outils sont déjà budgétés dans la filière ?</h3>
          </div>
          <span className="byi-caption">{data.respondents.filter(r=>(r.licences||[]).length>0).length} entreprises avec licences</span>
        </div>
        <div className="dash__lic">
          <div>
            <div className="dash__panel-sublabel">Statut licences (parmi utilisateurs IA)</div>
            <HBar
              data={agg.paidStatus.map((p, i) => ({
                ...p,
                color: p.label.startsWith("Oui") ? "var(--success)"
                  : p.label === "En cours de réflexion" ? "var(--byi-orange-500)" : "var(--byi-navy-300)"
              }))}
              height={20}
            />
          </div>
          <div>
            <div className="dash__panel-sublabel">Top outils souscrits (sièges cumulés)</div>
            <table className="dash__lic-table">
              <thead>
                <tr><th>Outil</th><th>Entreprises</th><th>Sièges totaux</th></tr>
              </thead>
              <tbody>
                {agg.licencesData.slice(0, 8).map(l => (
                  <tr key={l.label}>
                    <td><strong>{l.label}</strong></td>
                    <td>{l.orgs}</td>
                    <td><span className="dash__lic-seats">{l.seats}</span></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </Card>

      {/* ===== Row 5 — Intentions de formation (LE bloc clé) ===== */}
      <Card padding="lg" className="dash__training">
        <div className="dash__panel-head">
          <div>
            <Eyebrow color="var(--byi-orange-500)">Intentions de formation · programmes</Eyebrow>
            <h3 className="byi-h3" style={{ marginTop: 4 }}>Quels sujets de formation IA intéressent les adhérents FESPA France</h3>
          </div>
          <div className="dash__training-headline">
            <div className="dash__training-headline-num">{totals.peopleToTrain.toLocaleString("fr-FR")}</div>
            <div>personnes à former<br/><span className="byi-caption">~{Math.round(totals.trainingRevenue/1000).toLocaleString("fr-FR")} k€ potentiels</span></div>
          </div>
        </div>

        {/* Funnel of intent */}
        <div className="dash__intent-funnel">
          {agg.wantsFormation.map((w, i) => {
            const pct = Math.round(w.value / data.respondents.length * 100);
            const isPos = w.label.startsWith("Oui");
            return (
              <div key={w.label} className={`dash__intent-step ${isPos ? "is-pos" : ""}`}>
                <div className="dash__intent-step-pct">{pct}%</div>
                <div className="dash__intent-step-label">{w.label}</div>
                <div className="dash__intent-step-count">{w.value} adhérents</div>
              </div>
            );
          })}
        </div>

        <div className="dash__training-grid">
          <div className="dash__training-left">
            <div>
              <div className="dash__panel-sublabel">Thèmes plébiscités <span style={{fontWeight:400,letterSpacing:0,textTransform:"none"}}>(nb de répondants)</span></div>
              <HBar
                data={agg.themesWeighted.map((t, i) => ({
                  ...t,
                  color: i < 3 ? "var(--byi-orange-500)" : "var(--byi-orange-300)"
                }))}
                height={22}
              />
            </div>

            <div>
              <div className="dash__panel-sublabel">Apprenants à former · par module</div>
              <HBar
                data={agg.moduleTrainees.map((t, i) => ({
                  ...t,
                  color: i < 3 ? "var(--accent)" : "var(--byi-orange-300)"
                }))}
                height={22}
              />
            </div>

            <div>
              <div className="dash__panel-sublabel">Budget par personne</div>
              <div className="dash__budget">
                {agg.budget.map((b) => (
                  <div key={b.label} className="dash__budget-row">
                    <div className="dash__budget-lbl">{b.label}</div>
                    <div className="dash__budget-bar">
                      <div className="dash__budget-fill"
                        style={{
                          width: `${(b.value / Math.max(...agg.budget.map(x => x.value))) * 100}%`,
                          background: b.label.includes("Je ne sais pas") ? "var(--byi-navy-300)" : "var(--byi-orange-500)"
                        }}></div>
                    </div>
                    <div className="dash__budget-val">{b.value}</div>
                  </div>
                ))}
              </div>
            </div>
          </div>

          <div className="dash__training-side">
            <div>
              <div className="dash__panel-sublabel">Personnes à former · par service</div>
              <HBar
                data={agg.headcountByService.map((t, i) => ({
                  ...t, color: PALETTE[i % PALETTE.length]
                }))}
                height={18}
              />
            </div>

            <div>
              <div className="dash__panel-sublabel">Modules les plus demandés · par service</div>
              <div className="dash__modservice">
                {agg.modulesByService
                  .filter(ms => ms.modules.length > 0)
                  .slice(0, 5)
                  .map(ms => (
                    <div key={ms.service} className="dash__modservice-row">
                      <div className="dash__modservice-svc">{ms.service}</div>
                      <div className="dash__modservice-modules">
                        {ms.modules.slice(0, 3).map((m, i) => (
                          <span key={m.label} className={`dash__modservice-mod ${i === 0 ? "is-top" : ""}`}
                            title={`${m.label} — ${m.value} entreprises`}>
                            <span className="dash__modservice-mod-pill">{m.value}</span>
                            {m.label}
                          </span>
                        ))}
                      </div>
                    </div>
                  ))}
              </div>
            </div>

            <div>
              <div className="dash__panel-sublabel">Décideur formation</div>
              <div className="dash__chips">
                {agg.decider.map((t) => (
                  <div key={t.label} className="dash__chips-item dash__chips-item--alt">
                    <strong>{t.value}</strong>
                    <span>{t.label}</span>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>

        <div className="dash__training-cta">
          <ul className="dash__training-bullets">
            <li>
              <span className="dash__training-bullet-num">{wantsFormation.length}</span>
              <span className="dash__training-bullet-lbl">adhérents intéressés</span>
            </li>
            <li>
              <span className="dash__training-bullet-num">{totals.peopleToTrain.toLocaleString("fr-FR")}</span>
              <span className="dash__training-bullet-lbl">collaborateurs à former</span>
            </li>
          </ul>
        </div>
      </Card>

      {/* ===== Row 6 — Gouvernance, freins, déjà formés ===== */}
      <div className="dash__row dash__row--3col">
        <Card padding="lg" className="dash__panel">
          <Eyebrow>Politique d'usage IA en interne</Eyebrow>
          <div className="dash__policy">
            {satOrder.map(([label, color]) => {
              const v = (agg.policy.find(p => p.label === label) || {value:0}).value;
              const pct = Math.round(v / data.respondents.length * 100);
              return (
                <div key={label} className="dash__policy-row">
                  <div className="dash__policy-bar">
                    <div className="dash__policy-fill"
                      style={{ height: `${Math.max(pct, 4)}%`, background: color }}>
                      <span>{pct}%</span>
                    </div>
                  </div>
                  <div className="dash__policy-lbl">{label.replace("Oui, une charte ou politique formalisée","Charte formalisée").replace("Oui, des règles informelles","Règles informelles").replace("Non, mais c'est en réflexion","En réflexion").replace("Non, pas du tout","Aucune")}</div>
                </div>
              );
            })}
          </div>
        </Card>

        <Card padding="lg" className="dash__panel">
          <Eyebrow>Principaux freins identifiés</Eyebrow>
          <HBar
            data={agg.barriers.slice(0, 6).map((b, i) => ({
              ...b, color: i < 2 ? "var(--byi-coral-500)" : "var(--byi-navy-300)"
            }))}
            height={18}
          />
        </Card>

        <Card padding="lg" className="dash__panel">
          <Eyebrow>Maturité formation</Eyebrow>
          <div className="dash__matur">
            <DonutChart
              value={agg.pastTrained} total={data.respondents.length} size={140} stroke={14}
              color="var(--byi-cyan-500)"
              label={`${Math.round(100*agg.pastTrained/data.respondents.length)}%`}
              sublabel={`${agg.pastTrained} déjà formés`}
            />
            <div className="dash__matur-side">
              <p><strong>{agg.pastTrained}</strong> adhérents ont déjà suivi une formation IA.</p>
              <p className="byi-caption">{data.respondents.length - agg.pastTrained} restent à former — cible prioritaire de la Commission.</p>
              <div className="dash__matur-domains">
                <div className="dash__panel-sublabel">Domaines d'usage</div>
                <HBar
                  data={agg.domains.slice(0, 4).map((d, i) => ({
                    ...d, color: PALETTE[i % PALETTE.length]
                  }))}
                  height={14}
                />
              </div>
            </div>
          </div>
        </Card>
      </div>

      {/* ===== Row 7 — Latest respondents ===== */}
      <Card padding="lg" className="dash__panel dash__latest">
        <div className="dash__panel-head">
          <div>
            <Eyebrow>Derniers questionnaires reçus</Eyebrow>
            <h3 className="byi-h4">10 réponses les plus récentes</h3>
          </div>
          <Button variant="ghost">Voir tous les répondants →</Button>
        </div>
        <table className="dash__table">
          <thead>
            <tr>
              <th>Reçu le</th><th>Entreprise</th><th>Secteur</th><th>Effectif</th>
              <th>Usage</th><th>Niveau</th><th>Pers. à former</th><th></th>
            </tr>
          </thead>
          <tbody>
            {[...data.respondents].sort((a,b)=>b.submittedAt-a.submittedAt).slice(0, 10).map(r => (
              <tr key={r.id} onClick={() => onOpenRespondent(r.id)}>
                <td>{formatDate(r.submittedAt)}</td>
                <td><strong>{r.company}</strong></td>
                <td>{r.sectors.join(", ")}</td>
                <td>{r.sizeLabel.replace(" salariés","")}</td>
                <td><UsageDot usage={r.usage} /></td>
                <td><span className="dash__niveau">{r.skill}<small>/10</small></span></td>
                <td>{r.trainTotal > 0 ? <strong>{r.trainTotal}</strong> : <span style={{color:"var(--fg-muted)"}}>—</span>}</td>
                <td className="dash__table-arrow">→</td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

function UsageDot({ usage }) {
  const map = {
    "Oui, régulièrement": ["var(--success)", "Régulier"],
    "Oui, occasionnellement": ["var(--byi-teal-500)", "Occasionnel"],
    "Nous sommes en phase de test": ["var(--byi-orange-500)", "Test"],
    "Non, mais nous y réfléchissons": ["var(--byi-yellow-500)", "Réflexion"],
    "Non, pas du tout": ["var(--byi-coral-500)", "Non"]
  };
  const [color, label] = map[usage] || ["var(--fg-muted)", usage];
  return <span className="usage-dot"><span className="usage-dot__c" style={{background:color}}></span>{label}</span>;
}

function formatDate(d) {
  const days = Math.floor((new Date(2026, 4, 23) - d) / (1000 * 60 * 60 * 24));
  if (days === 0) return `Aujourd'hui · ${pad(d.getHours())}:${pad(d.getMinutes())}`;
  if (days === 1) return "Hier";
  if (days < 7) return `il y a ${days} j`;
  return d.toLocaleDateString("fr-FR", { day: "2-digit", month: "short" });
}
function pad(n) { return String(n).padStart(2, "0"); }

/* ============================================================
   Respondents list
   ============================================================ */
function AdminRespondents({ data, onOpen }) {
  const [search, setSearch] = useStateB("");
  const [filter, setFilter] = useStateB("all");

  const rows = data.respondents.filter(r => {
    const matchSearch = !search ||
      [r.company, r.firstName, r.lastName, r.email, ...(r.sectors||[])].join(" ").toLowerCase().includes(search.toLowerCase());
    const matchFilter = filter === "all" ||
      (filter === "users" && r.isUser) ||
      (filter === "non" && !r.isUser) ||
      (filter === "intent" && r.wantsFormation !== "Non, pas pour l'instant" && r.trainTotal > 0) ||
      (filter === "paid" && (r.licences || []).length > 0);
    return matchSearch && matchFilter;
  }).sort((a,b)=>b.submittedAt-a.submittedAt);

  return (
    <div className="resp">
      <div className="dash__head">
        <div>
          <Eyebrow>Tous les répondants</Eyebrow>
          <h1 className="byi-h2 dash__title">{data.respondents.length} questionnaires reçus</h1>
        </div>
        <Button variant="ghost" icon="⬇" onClick={() => exportRespondentsCSV(rows, data.catalog)}>Exporter en CSV</Button>
      </div>

      <div className="resp__filters">
        <input
          className="resp__search"
          placeholder="🔍 Rechercher entreprise, nom, email, secteur…"
          value={search}
          onChange={e => setSearch(e.target.value)}
        />
        <div className="resp__tabs">
          {[
            ["all", `Tous (${data.respondents.length})`],
            ["users", `Utilisateurs IA (${data.respondents.filter(r=>r.isUser).length})`],
            ["non", `Non-utilisateurs (${data.respondents.filter(r=>!r.isUser).length})`],
            ["intent", `Avec intention formation (${data.respondents.filter(r=>r.wantsFormation!=="Non, pas pour l'instant"&&r.trainTotal>0).length})`],
            ["paid", `Avec licences payantes (${data.respondents.filter(r=>(r.licences||[]).length>0).length})`]
          ].map(([id, label]) => (
            <button key={id} onClick={() => setFilter(id)} className={`resp__tab ${filter===id?"is-active":""}`}>
              {label}
            </button>
          ))}
        </div>
      </div>

      <Card padding="md" className="resp__table-wrap">
        <table className="dash__table dash__table--full">
          <thead>
            <tr>
              <th>Reçu</th><th>Entreprise</th><th>Répondant</th><th>Secteur</th><th>Eff.</th>
              <th>OPCO salariés</th><th>Usage IA</th><th>Niv.</th><th>Pers.</th><th>Budget</th><th></th>
            </tr>
          </thead>
          <tbody>
            {rows.map(r => (
              <tr key={r.id} onClick={() => onOpen(r.id)}>
                <td>{formatDate(r.submittedAt)}</td>
                <td><strong>{r.company}</strong></td>
                <td>{r.firstName} {r.lastName}<br/><span className="byi-caption">{r.role}</span></td>
                <td>{r.sectors.join(", ")}</td>
                <td>{r.sizeLabel.replace(" salariés","")}</td>
                <td>{(r.opcoSalaries || [])[0] || <span style={{color:"var(--fg-muted)"}}>—</span>}</td>
                <td><UsageDot usage={r.usage}/></td>
                <td><span className="dash__niveau">{r.skill}</span></td>
                <td>{r.trainTotal > 0 ? <strong>{r.trainTotal}</strong> : <span style={{color:"var(--fg-muted)"}}>—</span>}</td>
                <td>{r.budget === "unsure" ? <span style={{color:"var(--fg-muted)"}}>—</span> : <span className="byi-caption">{r.budgetLabel}</span>}</td>
                <td className="dash__table-arrow">→</td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

/* ============================================================
   Respondent detail
   ============================================================ */
function AdminRespondentDetail({ data, id, onBack, onNext, onPrev }) {
  const r = data.respondents.find(x => x.id === id);
  if (!r) return null;
  return (
    <div className="rd">
      <div className="rd__head">
        <button className="rd__back" onClick={onBack}>← Retour à la liste</button>
        <div className="rd__nav">
          <button onClick={onPrev}>← précédent</button>
          <button onClick={onNext}>suivant →</button>
        </div>
      </div>

      <div className="rd__top">
        <div>
          <Eyebrow>Questionnaire · {r.id}</Eyebrow>
          <h1 className="byi-h2 rd__title">{r.company}</h1>
          <div className="rd__meta">
            <span>{r.firstName} {r.lastName}</span>
            <span>·</span>
            <span>{r.role}</span>
            <span>·</span>
            <span>{r.email}</span>
          </div>
          <div className="rd__meta">
            {r.sectors.map(s => <Chip key={s} tone="navy-soft">{s}</Chip>)}
            <Chip tone="navy-soft">{r.sizeLabel}</Chip>
            <Chip tone="navy-soft">OPCO sal. : {r.opcoSalaries.join(", ")}</Chip>
            <Chip tone="navy-soft">OPCO dir. : {r.opcoDirigeant.join(", ")}</Chip>
          </div>
        </div>
        <div className="rd__head-actions">
          <Chip tone="accent">Reçu {formatDate(r.submittedAt)}</Chip>
          <Button variant="ghost">Exporter PDF</Button>
        </div>
      </div>

      <div className="rd__grid">
        <Card padding="lg" className="rd__panel">
          <Eyebrow>Usage actuel (Q5–Q10)</Eyebrow>
          <div className="rd__big"><UsageDot usage={r.usage}/></div>
          <Section title="Niveau IA déclaré (Q5)">
            <div className="rd__skill">
              {Array.from({length:10},(_,i)=>(
                <span key={i} className={`rd__skill-bar ${i<r.skill?"is-on":""}`}></span>
              ))}
              <strong>{r.skill}/10</strong>
            </div>
          </Section>
          <Section title="Outils utilisés (Q7)">
            {r.tools.length
              ? <div className="rd__chips">{r.tools.map(t => <Chip key={t} tone="navy-soft">{t}</Chip>)}</div>
              : <span className="byi-caption">Aucun outil renseigné</span>}
          </Section>
          <Section title="Licences payantes (Q8)">
            <div className="rd__big" style={{fontSize:14,marginTop:0}}>{r.paidStatus}</div>
            {r.licences.length > 0 && (
              <table className="rd__lic">
                <tbody>
                  {r.licences.map(l => (
                    <tr key={l.tool}><td>{l.tool}</td><td><strong>{l.count} sièges</strong></td></tr>
                  ))}
                </tbody>
              </table>
            )}
          </Section>
          <Section title="Domaines d'usage (Q9)">
            {r.domains.length
              ? <div className="rd__chips">{r.domains.map(t => <Chip key={t} tone="orange-soft">{t}</Chip>)}</div>
              : <span className="byi-caption">—</span>}
          </Section>
          <Section title="Bénéfices observés (Q10)">
            {r.benefits.length
              ? <div className="rd__chips">{r.benefits.map(t => <Chip key={t} tone="success-soft">{t}</Chip>)}</div>
              : <span className="byi-caption">—</span>}
          </Section>
        </Card>

        <Card padding="lg" className="rd__panel">
          <Eyebrow>Gouvernance & freins (Q11–Q12)</Eyebrow>
          <Section title="Politique d'usage IA (Q11)">
            <strong>{r.policy}</strong>
          </Section>
          <Section title="Principaux freins (Q12)">
            {r.barriers.length
              ? <div className="rd__chips">{r.barriers.map(t => <Chip key={t} tone="danger-soft">{t}</Chip>)}</div>
              : <span className="byi-caption">—</span>}
          </Section>

          <Section title="Formation déjà suivie (Q13)">
            {r.pastTraining ? (
              <div className="rd__past">
                <div><span>Intitulé</span><strong>{r.pastTraining.title}</strong></div>
                <div><span>Organisme</span><strong>{r.pastTraining.organism}</strong></div>
                <div><span>Effectif formé</span><strong>{r.pastTraining.headcount}</strong></div>
                <div><span>Année</span><strong>{r.pastTraining.year}</strong></div>
              </div>
            ) : <span className="byi-caption">Aucune formation suivie</span>}
          </Section>
        </Card>

        <Card padding="lg" className="rd__panel rd__panel--accent">
          <Eyebrow color="var(--byi-orange-500)">Intention de formation (Q15–Q18)</Eyebrow>
          <div className="rd__intent">
            <div className="rd__big" style={{marginBottom:0}}>{r.wantsFormation}</div>

            {r.trainTotal > 0 && r.trainingPlan && (
              <div>
                <span>Plan de formation par service (Q16)</span>
                <div className="rd__plan">
                  {Object.entries(r.trainingPlan)
                    .filter(([, p]) => Number(p.headcount) > 0 || (p.themes||[]).length > 0)
                    .map(([s, p]) => (
                      <div key={s} className="rd__plan-card">
                        <div className="rd__plan-head">
                          <strong>{s}</strong>
                          <span className="rd__plan-num">{p.headcount} apprenant{p.headcount > 1 ? "s" : ""}</span>
                        </div>
                        <div className="rd__plan-modules">
                          {(p.themes||[]).map(m => <Chip key={m} tone="accent">{m}</Chip>)}
                          {(p.themes||[]).length === 0 && <span className="byi-caption">Aucun module sélectionné</span>}
                        </div>
                      </div>
                    ))}
                  <div className="rd__plan-total">
                    <span>TOTAL</span>
                    <strong>{r.trainTotal} apprenants</strong>
                  </div>
                </div>
              </div>
            )}

            <div>
              <span>Modules sélectionnés (Q16)</span>
              <div className="rd__chips" style={{marginTop:8}}>
                {r.themes.map(t => <Chip key={t} tone="accent">{t}</Chip>)}
                {r.themes.length === 0 && <span className="byi-caption">Aucun module</span>}
              </div>
            </div>

            <div className="rd__intent-grid">
              <div><span>Budget / personne (Q17)</span><strong>{r.budgetLabel}</strong></div>
              <div><span>Décideur (Q18)</span><strong>{r.decider}</strong></div>
              <div><span>Atelier témoignage (Q19)</span><strong>{r.willingToShare}</strong></div>
              <div><span>Potentiel estimé</span><strong>{(r.trainTotal * r.budgetMid).toLocaleString("fr-FR")} €</strong></div>
            </div>
          </div>
        </Card>

        {r.comment && (
          <Card padding="lg" className="rd__panel rd__panel--comment">
            <Eyebrow>Commentaire libre (Q20)</Eyebrow>
            <p className="rd__quote">« {r.comment} »</p>
          </Card>
        )}
      </div>
    </div>
  );
}

function Section({ title, children }) {
  return (
    <div className="rd__section">
      <div className="rd__section-title">{title}</div>
      <div>{children}</div>
    </div>
  );
}

/* ============================================================
   Invitations
   ============================================================ */
function AdminInvitations({ data }) {
  const [showAddModal, setShowAddModal] = useStateB(false);
  const [showImportModal, setShowImportModal] = useStateB(false);
  const [addedMembers, setAddedMembers] = useStateB([]);
  const [newMember, setNewMember] = useStateB({
    company: "", contact: "", email: "", phone: "", role: "", region: "Île-de-France"
  });
  const [toast, setToast] = useStateB(null);

  // ===== Import state =====
  const [importStep, setImportStep] = useStateB("upload"); // upload | preview | done
  const [importRows, setImportRows] = useStateB([]);       // [{company, firstName, lastName, email, phone, valid, errors}]
  const [importFileName, setImportFileName] = useStateB("");
  const [importErrorCount, setImportErrorCount] = useStateB(0);
  const fileInputRef = React.useRef(null);

  const parseCSV = (text) => {
    // Robust CSV/TSV parsing — supports ; , or \t delimiters
    const lines = text.replace(/\r\n?/g, "\n").split("\n").filter(l => l.trim().length > 0);
    if (lines.length === 0) return [];
    const detectSep = (line) => {
      const counts = { ";": (line.match(/;/g) || []).length,
                       ",": (line.match(/,/g) || []).length,
                       "\t": (line.match(/\t/g) || []).length };
      return Object.entries(counts).sort((a, b) => b[1] - a[1])[0][0];
    };
    const sep = detectSep(lines[0]);
    const parseLine = (l) => {
      // simple CSV parser respecting double-quoted fields
      const out = []; let cur = ""; let inQ = false;
      for (let i = 0; i < l.length; i++) {
        const c = l[i];
        if (inQ) {
          if (c === '"' && l[i+1] === '"') { cur += '"'; i++; }
          else if (c === '"') inQ = false;
          else cur += c;
        } else {
          if (c === '"') inQ = true;
          else if (c === sep) { out.push(cur); cur = ""; }
          else cur += c;
        }
      }
      out.push(cur);
      return out.map(x => x.trim());
    };
    const header = parseLine(lines[0]).map(h => h.toLowerCase());
    // find columns by name
    const findCol = (...names) => {
      for (const n of names) {
        const i = header.findIndex(h => h.includes(n));
        if (i >= 0) return i;
      }
      return -1;
    };
    const colCompany   = findCol("société", "societe", "entreprise", "company");
    const colFirstName = findCol("prénom", "prenom", "first");
    const colLastName  = findCol("nom", "last");
    const colEmail     = findCol("mail", "email", "courriel");
    const colPhone     = findCol("gsm", "tél", "tel", "phone", "mobile");

    const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    const rows = [];
    for (let i = 1; i < lines.length; i++) {
      const cells = parseLine(lines[i]);
      const r = {
        company:   colCompany   >= 0 ? cells[colCompany]   || "" : "",
        firstName: colFirstName >= 0 ? cells[colFirstName] || "" : "",
        lastName:  colLastName  >= 0 ? cells[colLastName]  || "" : "",
        email:     colEmail     >= 0 ? cells[colEmail]     || "" : "",
        phone:     colPhone     >= 0 ? cells[colPhone]     || "" : "",
      };
      const errors = [];
      if (!r.company) errors.push("Société manquante");
      if (!r.email) errors.push("Email manquant");
      else if (!emailRe.test(r.email)) errors.push("Email invalide");
      r.valid = errors.length === 0;
      r.errors = errors;
      rows.push(r);
    }
    return rows;
  };

  const handleFileSelect = (file) => {
    if (!file) return;
    setImportFileName(file.name);
    const reader = new FileReader();
    reader.onload = (e) => {
      const rows = parseCSV(e.target.result);
      setImportRows(rows);
      setImportErrorCount(rows.filter(r => !r.valid).length);
      setImportStep("preview");
    };
    reader.readAsText(file, "UTF-8");
  };

  const downloadTemplate = () => {
    const csv = "\uFEFF" + [
      "Société;Prénom;Nom;Email;GSM",
      "Imprimerie Lemercier;Camille;Rousseau;c.rousseau@lemercier.fr;06 12 34 56 78",
      "Graphi-Print Solutions;Julien;Martin;j.martin@graphiprint.fr;06 98 76 54 32"
    ].join("\r\n");
    const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = "FESPA-import-adherents-modele.csv";
    document.body.appendChild(a); a.click(); document.body.removeChild(a);
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  };

  const confirmImport = () => {
    const valid = importRows.filter(r => r.valid).map(r => ({
      company: r.company,
      contact: `${r.firstName} ${r.lastName}`.trim(),
      email: r.email,
      phone: r.phone,
      role: "Dirigeant",
      region: "Île-de-France"
    }));
    setAddedMembers(arr => [...valid, ...arr]);
    setToast(`✓ ${valid.length} adhérents importés depuis ${importFileName}`);
    setShowImportModal(false);
    setImportStep("upload");
    setImportRows([]);
    setImportFileName("");
    setTimeout(() => setToast(null), 5000);
  };

  const closeImport = () => {
    setShowImportModal(false);
    setImportStep("upload");
    setImportRows([]);
    setImportFileName("");
    setImportErrorCount(0);
  };

  const [showTestModal, setShowTestModal] = useStateB(false);
  const [testEmail, setTestEmail] = useStateB("");
  const [testSubject, setTestSubject] = useStateB("Enquête FESPA France — Usage de l'IA dans votre entreprise");
  const [testBody, setTestBody] = useStateB(
`Bonjour,

Dans le cadre des travaux de la Commission IA de FESPA France, nous lançons une enquête auprès des adhérents sur l'usage de l'IA.

Temps estimé : 4 minutes — 20 questions
Vos réponses seront analysées de manière anonyme.

Répondre au questionnaire :
https://enquete.fespa-france.fr/r/[lien-unique]

Merci par avance,
La Commission IA — FESPA France`
  );

  const buildMailto = () => {
    if (!testEmail) return "#";
    const subject = encodeURIComponent(testSubject);
    const body = encodeURIComponent(testBody);
    return `mailto:${encodeURIComponent(testEmail)}?subject=${subject}&body=${body}`;
  };

  const buildGmail = () => {
    if (!testEmail) return "#";
    const subject = encodeURIComponent(testSubject);
    const body = encodeURIComponent(testBody);
    return `https://mail.google.com/mail/?view=cm&fs=1&to=${encodeURIComponent(testEmail)}&su=${subject}&body=${body}`;
  };

  const buildOutlookWeb = () => {
    if (!testEmail) return "#";
    const subject = encodeURIComponent(testSubject);
    const body = encodeURIComponent(testBody);
    return `https://outlook.live.com/owa/?path=/mail/action/compose&to=${encodeURIComponent(testEmail)}&subject=${subject}&body=${body}`;
  };

  const downloadEml = () => {
    if (!testEmail) return;
    const headers = [
      `From: "FESPA France — Commission IA" <commission-ia@fespa-france.fr>`,
      `To: ${testEmail}`,
      `Subject: =?UTF-8?B?${btoa(unescape(encodeURIComponent(testSubject)))}?=`,
      `Date: ${new Date().toUTCString()}`,
      `MIME-Version: 1.0`,
      `Content-Type: text/plain; charset=UTF-8`,
      `Content-Transfer-Encoding: 8bit`,
      ``
    ].join("\r\n");
    const eml = headers + "\r\n" + testBody.replace(/\r?\n/g, "\r\n");
    const blob = new Blob([eml], { type: "message/rfc822" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `test-fespa-france.eml`;
    document.body.appendChild(a); a.click(); document.body.removeChild(a);
    setTimeout(() => URL.revokeObjectURL(url), 1000);
    setToast(`📄 Fichier .eml téléchargé — double-cliquez dessus pour l'ouvrir dans votre client mail`);
    setTimeout(() => setToast(null), 6000);
  };

  const copyAll = () => {
    const txt = `À : ${testEmail}\nObjet : ${testSubject}\n\n${testBody}`;
    navigator.clipboard.writeText(txt);
    setToast("✓ Email complet copié dans le presse-papier — collez-le dans Brevo / Mailchimp");
    setTimeout(() => setToast(null), 4000);
  };

  const allCompanies = data.catalog.COMPANIES;
  // Expand to 416 by suffixing the catalog when needed (FESPA has 416 adherents total)
  const expandedCompanies = (() => {
    const out = [];
    const base = allCompanies;
    const cities = ["Paris", "Lyon", "Toulouse", "Bordeaux", "Lille", "Nantes", "Marseille",
      "Strasbourg", "Rennes", "Reims", "Tours", "Le Havre", "Grenoble", "Dijon",
      "Angers", "Clermont", "Nîmes", "Annecy", "Montpellier", "Aix", "Caen"];
    for (let i = 0; i < 416; i++) {
      if (i < base.length) {
        out.push(base[i]);
      } else {
        const c = base[i % base.length];
        const city = cities[Math.floor(i / base.length) % cities.length];
        out.push(`${c} · ${city}`);
      }
    }
    return out;
  })();
  const baseList = expandedCompanies.map((c, i) => {
    const responded = i < data.respondents.length ? data.respondents[i] : null;
    return {
      company: c,
      contact: responded ? `${responded.firstName} ${responded.lastName}` : pickContact(i),
      email: responded ? responded.email : (`contact@${c.toLowerCase().replace(/[^a-z]/g,"").slice(0,12)}.fr`),
      sentAt: new Date(2026, 4, 23 - 18 - (i % 3)),
      reminders: i % 4,
      status: responded ? "responded" : (i % 5 === 0 ? "opened" : (i % 7 === 0 ? "bounced" : "pending")),
      isNew: false
    };
  });
  const list = [
    ...addedMembers.map(m => ({ ...m, sentAt: new Date(), reminders: 0, status: "pending", isNew: true })),
    ...baseList
  ];

  const totals = {
    sent: list.length,
    responded: list.filter(l => l.status === "responded").length,
    opened: list.filter(l => l.status === "opened").length,
    pending: list.filter(l => l.status === "pending").length,
    bounced: list.filter(l => l.status === "bounced").length
  };

  const handleAdd = (e) => {
    e.preventDefault();
    if (!newMember.company || !newMember.email) return;
    setAddedMembers(arr => [{ ...newMember }, ...arr]);
    setToast(`Adhérent « ${newMember.company} » ajouté · invitation envoyée à ${newMember.email}`);
    setNewMember({ company: "", contact: "", email: "", phone: "", role: "", region: "Île-de-France" });
    setShowAddModal(false);
    setTimeout(() => setToast(null), 4000);
  };

  return (
    <div className="inv">
      <div className="dash__head">
        <div>
          <Eyebrow>Gestion des invitations</Eyebrow>
          <h1 className="byi-h2 dash__title">Liens personnalisés envoyés aux adhérents</h1>
        </div>
        <div className="dash__head-actions">
          <Button variant="ghost" icon="⬇">Exporter liste</Button>
          <Button variant="ghost" icon="✉" onClick={() => setShowTestModal(true)}>Tester l'envoi</Button>
          <Button variant="ghost" icon="📥" onClick={() => setShowImportModal(true)}>Importer la base</Button>
          <Button icon="＋" onClick={() => setShowAddModal(true)}>Ajouter un adhérent</Button>
        </div>
      </div>

      <div className="inv__kpis">
        <StatTile label="Invitations envoyées" value={totals.sent} tone="navy"/>
        <StatTile label="Questionnaires reçus" value={totals.responded} sub={`${Math.round(totals.responded/totals.sent*100)}% du fichier`} tone="success"/>
        <StatTile label="Liens ouverts non complétés" value={totals.opened} tone="orange"/>
        <StatTile label="Sans réponse" value={totals.pending} tone="muted"/>
        <StatTile label="Adresses invalides" value={totals.bounced} tone="danger"/>
      </div>

      <Card padding="md" className="resp__table-wrap">
        <div className="inv__toolbar">
          <input className="resp__search" placeholder="🔍 Filtrer par entreprise, contact…"/>
          <div className="inv__bulk">
            <button>Tout sélectionner</button>
            <Button size="sm">📨 Relancer la sélection</Button>
          </div>
        </div>
        <table className="dash__table dash__table--full">
          <thead>
            <tr>
              <th><input type="checkbox"/></th>
              <th>Entreprise</th><th>Contact</th><th>Email</th>
              <th>Envoyé le</th><th>Relances</th><th>Statut</th><th></th>
            </tr>
          </thead>
          <tbody>
            {list.slice(0, 40 + addedMembers.length).map((l, i) => (
              <tr key={i} className={l.isNew ? "inv__row--new" : ""}>
                <td><input type="checkbox" /></td>
                <td>
                  <strong>{l.company}</strong>
                  {l.isNew && <span className="inv__newbadge">Nouveau</span>}
                </td>
                <td>{l.contact}</td>
                <td><span className="byi-caption">{l.email}</span></td>
                <td>{formatDate(l.sentAt)}</td>
                <td>{l.reminders > 0 ? `${l.reminders}×` : <span style={{color:"var(--fg-muted)"}}>—</span>}</td>
                <td><StatusChip status={l.status}/></td>
                <td>
                  {l.status === "responded" ? <span className="byi-caption">Voir →</span>
                   : <button className="inv__relance">Relancer</button>}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>

      {/* ===== Add member modal ===== */}
      {showAddModal && (
        <div className="adm-modal" onClick={() => setShowAddModal(false)}>
          <form className="adm-modal__panel" onClick={e => e.stopPropagation()} onSubmit={handleAdd}>
            <div className="adm-modal__head">
              <div>
                <Eyebrow>Nouvel adhérent</Eyebrow>
                <h2 className="byi-h3 adm-modal__title">Ajouter un adhérent à l'enquête</h2>
              </div>
              <button type="button" className="adm-modal__close" onClick={() => setShowAddModal(false)}>×</button>
            </div>

            <p className="adm-modal__help">
              L'adhérent recevra par email un lien personnalisé pour répondre au questionnaire.
              Les champs marqués <span style={{color: "var(--danger)"}}>*</span> sont obligatoires.
            </p>

            <div className="adm-modal__body">
              <label className="qf-input qf-input--full">
                <span>Entreprise <span style={{color:"var(--danger)"}}>*</span></span>
                <input required value={newMember.company}
                  onChange={e => setNewMember(s => ({ ...s, company: e.target.value }))}
                  placeholder="Ex : Imprimerie Lemercier" />
              </label>
              <div className="qf-grid-2">
                <label className="qf-input">
                  <span>Nom du contact</span>
                  <input value={newMember.contact}
                    onChange={e => setNewMember(s => ({ ...s, contact: e.target.value }))}
                    placeholder="Prénom Nom" />
                </label>
                <label className="qf-input">
                  <span>Rôle / fonction</span>
                  <input value={newMember.role}
                    onChange={e => setNewMember(s => ({ ...s, role: e.target.value }))}
                    placeholder="Ex : Dirigeant, RH…" />
                </label>
                <label className="qf-input">
                  <span>Email <span style={{color:"var(--danger)"}}>*</span></span>
                  <input required type="email" value={newMember.email}
                    onChange={e => setNewMember(s => ({ ...s, email: e.target.value }))}
                    placeholder="contact@entreprise.fr" />
                </label>
                <label className="qf-input">
                  <span>Téléphone</span>
                  <input value={newMember.phone}
                    onChange={e => setNewMember(s => ({ ...s, phone: e.target.value }))}
                    placeholder="06 12 34 56 78" />
                </label>
                <label className="qf-input qf-input--full">
                  <span>Région</span>
                  <select className="qf-select" value={newMember.region}
                    onChange={e => setNewMember(s => ({ ...s, region: e.target.value }))}>
                    {data.catalog.REGIONS && data.catalog.REGIONS.map(r => <option key={r}>{r}</option>)}
                    {!data.catalog.REGIONS && <option>Île-de-France</option>}
                  </select>
                </label>
              </div>

              <div className="adm-modal__opts">
                <label className="adm-modal__check">
                  <input type="checkbox" defaultChecked /> Envoyer l'invitation par email immédiatement
                </label>
                <label className="adm-modal__check">
                  <input type="checkbox" /> Programmer une relance automatique sous 7 jours
                </label>
              </div>
            </div>

            <div className="adm-modal__footer">
              <Button variant="ghost" type="button" onClick={() => setShowAddModal(false)}>Annuler</Button>
              <Button type="submit">＋ Ajouter & envoyer l'invitation</Button>
            </div>
          </form>
        </div>
      )}

      {toast && (
        <div className="adm-toast">
          <span className="adm-toast__dot"></span>
          {toast}
        </div>
      )}

      {/* ===== Test email modal ===== */}
      {showTestModal && (
        <div className="adm-modal" onClick={() => setShowTestModal(false)}>
          <div className="adm-modal__panel adm-modal__panel--wide" onClick={e => e.stopPropagation()}>
            <div className="adm-modal__head">
              <div>
                <Eyebrow color="var(--byi-orange-500)">Test d'envoi d'email</Eyebrow>
                <h2 className="byi-h3 adm-modal__title">Recevez l'email exactement comme l'adhérent</h2>
              </div>
              <button type="button" className="adm-modal__close" onClick={() => setShowTestModal(false)}>×</button>
            </div>

            <p className="adm-modal__help">
              Saisissez votre adresse mail puis cliquez sur « Envoyer le test ».
              L'email s'ouvrira dans votre client de messagerie (Outlook, Gmail…) avec le sujet,
              le contenu et le lien personnalisé pré-remplis. Il vous suffit de cliquer sur Envoyer
              pour le recevoir et vérifier le rendu.
            </p>

            <div className="adm-modal__body">
              <div className="qf-grid-2">
                <label className="qf-input qf-input--full">
                  <span>Adresse mail de test <span style={{color:"var(--danger)"}}>*</span></span>
                  <input type="email" required value={testEmail}
                    onChange={e => setTestEmail(e.target.value)}
                    placeholder="votre.email@fespa-france.fr" />
                </label>
                <label className="qf-input qf-input--full">
                  <span>Objet de l'email</span>
                  <input value={testSubject} onChange={e => setTestSubject(e.target.value)} />
                </label>
              </div>

              <label className="qf-input qf-input--full">
                <span>Corps du message (modifiable)</span>
                <textarea className="qf-textarea" rows={14}
                  value={testBody}
                  onChange={e => setTestBody(e.target.value)}></textarea>
              </label>

              <div className="test-channels">
                <div className="test-channels__title">Méthode d'envoi du test</div>
                <p className="test-channels__hint">
                  Choisissez le canal qui correspond à votre boîte mail. Le contenu et le destinataire
                  sont pré-remplis automatiquement — il vous suffit de cliquer sur « Envoyer » dans
                  votre messagerie.
                </p>
                <div className="test-channels__grid">
                  <a className={`test-channel ${!testEmail ? "is-disabled" : ""}`}
                    href={buildMailto()} target="_top"
                    onClick={e => { if (!testEmail) e.preventDefault(); }}>
                    <div className="test-channel__icon">💻</div>
                    <div className="test-channel__name">Mon client mail (Outlook, Apple Mail…)</div>
                    <div className="test-channel__hint">Lien mailto: — nécessite un client mail configuré sur votre poste</div>
                  </a>
                  <a className={`test-channel ${!testEmail ? "is-disabled" : ""}`}
                    href={buildGmail()} target="_blank" rel="noopener noreferrer"
                    onClick={e => { if (!testEmail) e.preventDefault(); }}>
                    <div className="test-channel__icon">📨</div>
                    <div className="test-channel__name">Gmail (web)</div>
                    <div className="test-channel__hint">Ouvre un nouvel onglet de composition Gmail pré-rempli</div>
                  </a>
                  <a className={`test-channel ${!testEmail ? "is-disabled" : ""}`}
                    href={buildOutlookWeb()} target="_blank" rel="noopener noreferrer"
                    onClick={e => { if (!testEmail) e.preventDefault(); }}>
                    <div className="test-channel__icon">📧</div>
                    <div className="test-channel__name">Outlook (web)</div>
                    <div className="test-channel__hint">Ouvre un nouvel onglet Outlook.com pré-rempli</div>
                  </a>
                  <button type="button" className="test-channel" onClick={downloadEml} disabled={!testEmail}>
                    <div className="test-channel__icon">📄</div>
                    <div className="test-channel__name">Télécharger un fichier .eml</div>
                    <div className="test-channel__hint">Fichier email à double-cliquer — fonctionne avec tous les clients</div>
                  </button>
                </div>
                <button type="button" className="import-link" style={{marginTop:14}} onClick={copyAll}>
                  📋 Ou copier l'email complet (destinataire + objet + corps)
                </button>
              </div>

              <div className="test-tips">
                <div className="test-tips__title">💡 Pour l'envoi en masse aux 416 adhérents</div>
                <p>
                  Cette fonction est conçue pour <strong>tester le rendu</strong>. Pour l'envoi
                  réel à l'ensemble du fichier, utilisez un service professionnel
                  (<strong>Brevo</strong>, <strong>Mailchimp</strong>, <strong>Sarbacane</strong>) :
                </p>
                <ul>
                  <li>Importez le fichier exporté depuis « Exporter liste »</li>
                  <li>Collez le contenu copié ci-dessus comme template</li>
                  <li>Personnalisez avec <code>{`{{prenom}}`}</code> et le lien unique</li>
                  <li>Bénéficiez du suivi d'ouverture / clics / désinscription RGPD</li>
                </ul>
              </div>
            </div>

            <div className="adm-modal__footer">
              <Button variant="ghost" type="button" onClick={() => setShowTestModal(false)}>Fermer</Button>
            </div>
          </div>
        </div>
      )}

      {/* ===== Import database modal ===== */}
      {showImportModal && (
        <div className="adm-modal" onClick={closeImport}>
          <div className="adm-modal__panel adm-modal__panel--wide" onClick={e => e.stopPropagation()}>
            <div className="adm-modal__head">
              <div>
                <Eyebrow>Importer la base d'adhérents</Eyebrow>
                <h2 className="byi-h3 adm-modal__title">
                  {importStep === "upload" && "Importer un fichier CSV / Excel"}
                  {importStep === "preview" && `Aperçu — ${importRows.length} ligne${importRows.length > 1 ? "s" : ""}`}
                </h2>
              </div>
              <button type="button" className="adm-modal__close" onClick={closeImport}>×</button>
            </div>

            {importStep === "upload" && (
              <>
                <p className="adm-modal__help">
                  Le fichier doit contenir, au minimum, les colonnes suivantes (l'ordre n'a pas d'importance, les en-têtes sont reconnus automatiquement) :
                </p>
                <div className="adm-modal__body">
                  <div className="import-cols">
                    {[
                      ["Société", "Nom de l'entreprise adhérente", true],
                      ["Prénom", "Prénom du dirigeant / contact", false],
                      ["Nom", "Nom du dirigeant / contact", false],
                      ["Email", "Adresse mail principale", true],
                      ["GSM", "Téléphone mobile", false]
                    ].map(([name, hint, req]) => (
                      <div key={name} className="import-col">
                        <div className="import-col__name">
                          {name}
                          {req && <span className="import-col__req">obligatoire</span>}
                        </div>
                        <div className="import-col__hint">{hint}</div>
                      </div>
                    ))}
                  </div>

                  <div className="import-drop"
                    onClick={() => fileInputRef.current && fileInputRef.current.click()}
                    onDragOver={e => { e.preventDefault(); e.currentTarget.classList.add("is-over"); }}
                    onDragLeave={e => e.currentTarget.classList.remove("is-over")}
                    onDrop={e => {
                      e.preventDefault();
                      e.currentTarget.classList.remove("is-over");
                      const f = e.dataTransfer.files[0];
                      if (f) handleFileSelect(f);
                    }}>
                    <div className="import-drop__icon">📥</div>
                    <div className="import-drop__title">Cliquez ou déposez votre fichier ici</div>
                    <div className="import-drop__sub">
                      Formats acceptés : <strong>.csv</strong>, <strong>.txt</strong> (Excel : « Enregistrer sous » → CSV UTF-8)
                    </div>
                    <input ref={fileInputRef} type="file" accept=".csv,.txt,text/csv"
                      style={{display:"none"}}
                      onChange={e => handleFileSelect(e.target.files[0])} />
                  </div>

                  <div className="import-help-row">
                    <button type="button" className="import-link" onClick={downloadTemplate}>
                      ⬇ Télécharger le modèle CSV
                    </button>
                    <span className="byi-caption">
                      Séparateurs reconnus&nbsp;: virgule, point-virgule, tabulation
                    </span>
                  </div>
                </div>

                <div className="adm-modal__footer">
                  <Button variant="ghost" type="button" onClick={closeImport}>Annuler</Button>
                </div>
              </>
            )}

            {importStep === "preview" && (
              <>
                <div className="adm-modal__body">
                  <div className="import-stats">
                    <div className="import-stat import-stat--ok">
                      <span className="import-stat__num">{importRows.length - importErrorCount}</span>
                      <span className="import-stat__lbl">lignes valides</span>
                    </div>
                    {importErrorCount > 0 && (
                      <div className="import-stat import-stat--err">
                        <span className="import-stat__num">{importErrorCount}</span>
                        <span className="import-stat__lbl">ligne{importErrorCount>1?"s":""} en erreur</span>
                      </div>
                    )}
                    <div className="import-stat">
                      <span className="import-stat__num">{importRows.length}</span>
                      <span className="import-stat__lbl">total fichier</span>
                    </div>
                    <div className="import-file">📄 {importFileName}</div>
                  </div>

                  <div className="import-table-wrap">
                    <table className="dash__table dash__table--full import-table">
                      <thead>
                        <tr>
                          <th style={{width:30}}></th>
                          <th>Société</th><th>Prénom</th><th>Nom</th>
                          <th>Email</th><th>GSM</th><th>État</th>
                        </tr>
                      </thead>
                      <tbody>
                        {importRows.slice(0, 50).map((r, i) => (
                          <tr key={i} className={!r.valid ? "import-row--err" : ""}>
                            <td>{r.valid ? "✓" : "⚠"}</td>
                            <td><strong>{r.company || "—"}</strong></td>
                            <td>{r.firstName || "—"}</td>
                            <td>{r.lastName || "—"}</td>
                            <td><span className="byi-caption">{r.email || "—"}</span></td>
                            <td>{r.phone || <span style={{color:"var(--fg-muted)"}}>—</span>}</td>
                            <td>{r.valid
                              ? <Chip tone="success" size="sm">Prêt</Chip>
                              : <span className="import-err">{r.errors.join(" · ")}</span>}</td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                    {importRows.length > 50 && (
                      <div className="import-more">… et {importRows.length - 50} autres lignes</div>
                    )}
                  </div>
                </div>

                <div className="adm-modal__footer">
                  <Button variant="ghost" type="button" onClick={() => setImportStep("upload")}>← Recharger un fichier</Button>
                  <Button type="button" onClick={confirmImport} disabled={importRows.length === importErrorCount}>
                    ✓ Importer {importRows.length - importErrorCount} adhérent{importRows.length - importErrorCount > 1 ? "s" : ""}
                  </Button>
                </div>
              </>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

function StatusChip({ status }) {
  const map = {
    responded: ["var(--success)", "Répondu"],
    opened: ["var(--byi-orange-500)", "Ouvert · pas répondu"],
    pending: ["var(--byi-navy-300)", "En attente"],
    bounced: ["var(--byi-coral-500)", "Email invalide"]
  };
  const [c, l] = map[status];
  return <span className="status-chip" style={{ "--c": c }}><span></span>{l}</span>;
}

function pickContact(seed) {
  const FIRST = ["Sophie", "Julien", "Camille", "Antoine", "Marie", "Thomas", "Élodie", "Nicolas"];
  const LAST = ["Martin", "Bernard", "Dubois", "Petit", "Durand", "Leroy", "Moreau"];
  return `${FIRST[seed % FIRST.length]} ${LAST[seed % LAST.length]}`;
}

Object.assign(window, {
  AdminLogin, AdminShell, AdminDashboard, AdminRespondents,
  AdminRespondentDetail, AdminInvitations,
  AdminCampaigns, CampaignClosedNotice,
  ADMIN_AREAS, FESPA_CAMPAIGNS
});
