// NeoFlow — Calculateur Temps Perdu (Section § 05 de /immobilier)
// Remplace l'ancien composant <Audit /> en utilisant un diagnostic IA personnalisé.
//
// Inclusion dans index.html (à ajouter par sub-agent B) :
//   <script type="text/babel" src="cinetique/calculateur.jsx?v=13"></script>
//
// Spec de référence : Calculateur Temps Perdu — Spec Complète (Obsidian Vault § 3,4,6,7)
// Pattern : tous les composants exposés via window.* (pas de modules ES6)

const { useState: cUseState, useEffect: cUseEffect, useRef: cUseRef, useMemo: cUseMemo } = React;

/* ────────────────────────────────────────────────────────────
   Constantes
   ──────────────────────────────────────────────────────────── */

const CALC_WEBHOOK_URL  = 'https://n8n.srv1137119.hstgr.cloud/webhook/immo-calculateur';
const CALC_STORAGE_KEY  = 'neoflow_calculateur_state';
const CALC_TIMEOUT_MS   = 15000;

/* ── Rôles (étape 1) ── */
const CALC_ROLES = [
  { id: 'agent_agence',          label: 'Agent immobilier en agence (salarié)' },
  { id: 'directeur_agence',      label: "Directeur ou gérant d'agence" },
  { id: 'mandataire_independant',label: 'Mandataire / agent commercial indépendant' },
  { id: 'autre_metier_immo',     label: "Autre métier de l'immobilier (notaire, gestionnaire de patrimoine, promoteur, expert, syndic…)" },
];

/* ── Définitions des branches (cf. spec § 4.2 → 4.5) ──
   Chaque branche = liste d'étapes (1 question max par étape pour rester aéré sur mobile).
   Types supportés : choice (single), check (multi), text (textarea). */
const CALC_BRANCHES = {
  agent_agence: {
    code: 'A',
    label: 'Agent en agence',
    questions: [
      { id: 'taille_agence',   type: 'choice', label: 'Combien êtes-vous dans votre agence ?',
        options: ['1-2', '3-5', '6-15', '15+'] },
      { id: 'visites_semaine', type: 'choice', label: 'Combien de visites organisez-vous par semaine en moyenne ?',
        options: ['0-2', '3-5', '6-10', '10+'] },
      { id: 'apres_visite',    type: 'choice', label: 'Après une visite, vous faites quoi avec le propriétaire ?',
        options: ['Rien de systématique', 'Un appel rapide', 'Un email écrit', 'Un template structuré'] },
      { id: 'outil_agence',    type: 'choice', label: 'Quel outil utilise votre agence au quotidien ?',
        options: ['Rien de formel (Excel, papier)', 'Un CRM générique', 'Un logiciel métier (Hektor, Apimo, Netty…)', 'Je ne sais pas trop'] },
      { id: 'tache_chrono',    type: 'text',   label: "Qu'est-ce qui vous prend le plus de temps inutilement chaque semaine ?",
        placeholder: '1 ou 2 phrases — la réponse honnête est la plus utile.', rows: 4 },
    ],
  },
  directeur_agence: {
    code: 'B',
    label: "Directeur d'agence",
    questions: [
      { id: 'taille_equipe',   type: 'choice', label: 'Combien de personnes dans votre équipe ?',
        options: ['Juste moi', '2-5', '6-15', '15+'] },
      { id: 'mandats_actifs',  type: 'choice', label: 'Combien de mandats actifs en ce moment ?',
        options: ['1-10', '10-30', '30-60', '60+'] },
      { id: 'outil_actuel',    type: 'choice', label: 'Quel outil utilisez-vous aujourd\'hui ?',
        options: ['Excel + email + téléphone', 'Un CRM générique', 'Un logiciel métier (Hektor, Apimo, Netty, AC3…)', 'Autre'] },
      { id: 'satisfaction',    type: 'choice', label: 'Vous en êtes satisfait ?',
        options: ['Très satisfait', 'Ça fait le job', 'Pas vraiment', 'Pas du tout'],
        showIf: (a) => a.outil_actuel && a.outil_actuel.startsWith('Un logiciel métier') },
      { id: 'defis_top2',      type: 'check',  label: 'Quels sont vos 2 plus gros défis aujourd\'hui ?',
        options: ['Génération de leads', 'Conversion prospects', 'Suivi mandats', 'Gestion équipe', 'Reporting', 'Site web obsolète', 'Automatisations', 'Autre'] },
      { id: 'automatiser_1',   type: 'text',   label: 'Si vous pouviez automatiser une chose, ce serait quoi ?',
        placeholder: 'La tâche la plus pénible — celle que vous repoussez.', rows: 3 },
    ],
  },
  mandataire_independant: {
    code: 'C',
    label: 'Mandataire indépendant',
    questions: [
      { id: 'heures_admin',    type: 'choice', label: 'Combien d\'heures par semaine passez-vous sur l\'admin pur ?',
        options: ['< 2h', '2-5h', '5-10h', '10h+'] },
      { id: 'gestion_mandats', type: 'choice', label: 'Comment gérez-vous vos mandats et prospects ?',
        options: ['De tête', 'Carnet ou Excel', 'Logiciel dédié', 'Je gère mal, honnêtement'] },
      { id: 'visites_semaine', type: 'choice', label: 'Combien de visites organisez-vous par semaine ?',
        options: ['0-2', '3-5', '6-10', '10+'] },
      { id: 'site_pro',        type: 'choice', label: 'Avez-vous un site pro ?',
        options: ['Oui, il génère des leads', 'Oui mais peu de trafic', 'Non'] },
      { id: 'sources_prospects', type: 'check', label: 'D\'où viennent principalement vos prospects ?',
        options: ['Réseau', 'Bouche-à-oreille', 'Portails (SeLoger, LeBonCoin)', 'Réseaux sociaux', 'Site web', 'Pige'] },
      { id: 'a_disparaitre',   type: 'text',   label: 'Qu\'est-ce que vous aimeriez voir disparaître de votre quotidien ?',
        placeholder: 'Soyez précis — ça nous aide à voir les leviers concrets.', rows: 3 },
    ],
  },
  autre_metier_immo: {
    code: 'D',
    label: 'Autre métier de l\'immobilier',
    questions: [
      { id: 'activite_precise', type: 'text', label: 'Quelle est précisément votre activité ?',
        placeholder: 'Ex. notaire, syndic, promoteur, expert, gestionnaire de patrimoine…', rows: 2 },
      { id: 'taille_structure', type: 'choice', label: 'Combien de personnes dans votre structure ?',
        options: ['Juste moi', '2-5', '6-15', '15+'] },
      { id: 'outils_utilises',  type: 'check',  label: 'Quels outils utilisez-vous au quotidien ?',
        options: ['Logiciel métier', 'CRM', 'Outils bureautique (Word, Excel, Gmail…)', 'Signature électronique', 'Aucun outil dédié', 'Autre'] },
      { id: 'defis_top2',       type: 'check',  label: 'Quels sont vos 2 principaux défis aujourd\'hui ?',
        options: ['Présence en ligne', 'Gestion clients', 'Automatisations', 'Suivi des affaires', 'Communication interne', 'Autre'] },
      { id: 'a_disparaitre',    type: 'text',   label: 'Quelle tâche aimeriez-vous voir disparaître ?',
        placeholder: 'La plus pénible — celle qui vous coûte du temps sans valeur.', rows: 3 },
    ],
  },
};

/* ────────────────────────────────────────────────────────────
   Helpers
   ──────────────────────────────────────────────────────────── */

function calcSafeLoadState() {
  try {
    const raw = localStorage.getItem(CALC_STORAGE_KEY);
    if (!raw) return null;
    return JSON.parse(raw);
  } catch (_) { return null; }
}

function calcSafeSaveState(state) {
  try { localStorage.setItem(CALC_STORAGE_KEY, JSON.stringify(state)); } catch (_) {}
}

function calcClearState() {
  try { localStorage.removeItem(CALC_STORAGE_KEY); } catch (_) {}
}

function calcGetUtmSource() {
  try {
    const url = new URL(window.location.href);
    return url.searchParams.get('utm_source') || null;
  } catch (_) { return null; }
}

function calcPosthog(event, props) {
  try {
    if (window.posthog && typeof window.posthog.capture === 'function') {
      window.posthog.capture(event, props || {});
    }
  } catch (_) {}
}

/* Validation : pour une question, est-elle "remplie" ? */
function calcIsAnswered(q, value) {
  if (q.type === 'choice') return !!value;
  if (q.type === 'check')  return Array.isArray(value) && value.length > 0;
  if (q.type === 'text')   return typeof value === 'string' && value.trim().length > 0;
  return true;
}

/* Pourcentage de barre pour le breakdown — borné à 95% pour laisser une marge visuelle */
function calcBarPercent(hours, maxHours) {
  if (!maxHours || maxHours <= 0) return 0;
  const p = (hours / maxHours) * 100;
  return Math.max(6, Math.min(95, p));
}

/* ────────────────────────────────────────────────────────────
   Sous-composants UI
   ──────────────────────────────────────────────────────────── */

/* Bouton choix unique — version interne (la classe globale .choice-btn ne suffit pas car on veut palette immo) */
function CalcChoice({ options, value, onChange }) {
  return (
    <div className="calc-choice-group">
      {options.map((opt, i) => (
        <button
          key={i}
          type="button"
          className={`calc-choice-btn ${value === opt ? 'is-selected' : ''}`}
          onClick={() => onChange(opt)}
        >
          <span className="calc-choice-letter">{String.fromCharCode(65 + i)}</span>
          <span className="calc-choice-label">{opt}</span>
        </button>
      ))}
    </div>
  );
}

/* Cases à cocher multi-select */
function CalcCheckGroup({ options, value, onChange }) {
  function toggle(opt) {
    const next = value.includes(opt) ? value.filter(v => v !== opt) : [...value, opt];
    onChange(next);
  }
  return (
    <div className="calc-check-group">
      {options.map((opt, i) => (
        <label
          key={i}
          className={`calc-check-item ${value.includes(opt) ? 'is-checked' : ''}`}
        >
          <input
            type="checkbox"
            checked={value.includes(opt)}
            onChange={() => toggle(opt)}
          />
          <span className="calc-check-box" aria-hidden="true">
            {value.includes(opt) && (
              <svg width="10" height="8" viewBox="0 0 10 8" fill="none">
                <path d="M1 4l3 3 5-6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
            )}
          </span>
          <span>{opt}</span>
        </label>
      ))}
    </div>
  );
}

/* Barre de progression simple — segments comme dans immo-forms */
function CalcProgress({ step, total }) {
  return (
    <div className="calc-progress" role="progressbar" aria-valuemin={1} aria-valuenow={step + 1} aria-valuemax={total}>
      {Array.from({ length: total }).map((_, i) => (
        <div key={i} className={`calc-progress-seg ${i <= step ? 'is-done' : ''}`}></div>
      ))}
    </div>
  );
}

/* ────────────────────────────────────────────────────────────
   Étape 1 — Identité (universelle)
   ──────────────────────────────────────────────────────────── */

function CalcIdentityStep({ identity, setIdentity }) {
  return (
    <div className="calc-step">
      <div className="calc-q">
        <label className="calc-q-label" htmlFor="calc-prenom">Votre prénom</label>
        <input
          id="calc-prenom"
          className="calc-input"
          type="text"
          autoComplete="given-name"
          required
          value={identity.prenom}
          onChange={e => setIdentity({ ...identity, prenom: e.target.value })}
          placeholder="Ex. Marie"
        />
      </div>
      <div className="calc-q">
        <label className="calc-q-label" htmlFor="calc-email">Votre email</label>
        <input
          id="calc-email"
          className="calc-input"
          type="email"
          autoComplete="email"
          required
          value={identity.email}
          onChange={e => setIdentity({ ...identity, email: e.target.value })}
          placeholder="votre@email.com"
        />
        <p className="calc-q-hint">On vous envoie votre diagnostic. Pas de spam, jamais.</p>
      </div>
      <div className="calc-q">
        <label className="calc-q-label" htmlFor="calc-ville">Votre ville ou région</label>
        <input
          id="calc-ville"
          className="calc-input"
          type="text"
          autoComplete="address-level2"
          required
          value={identity.ville}
          onChange={e => setIdentity({ ...identity, ville: e.target.value })}
          placeholder="Ex. Nantes, Île-de-France, PACA…"
        />
      </div>
      <div className="calc-q">
        <span className="calc-q-label">Vous êtes ?</span>
        <CalcChoice
          options={CALC_ROLES.map(r => r.label)}
          value={CALC_ROLES.find(r => r.id === identity.role) ? CALC_ROLES.find(r => r.id === identity.role).label : ''}
          onChange={(label) => {
            const role = CALC_ROLES.find(r => r.label === label);
            setIdentity({ ...identity, role: role ? role.id : '' });
          }}
        />
      </div>
    </div>
  );
}

function calcIdentityValid(identity) {
  if (!identity.prenom || !identity.prenom.trim()) return false;
  if (!identity.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(identity.email)) return false;
  if (!identity.ville || !identity.ville.trim()) return false;
  if (!identity.role) return false;
  return true;
}

/* ────────────────────────────────────────────────────────────
   Étapes de branche — rendu d'une question
   ──────────────────────────────────────────────────────────── */

function CalcBranchQuestion({ question, value, onChange }) {
  return (
    <div className="calc-step">
      <div className="calc-q">
        <span className="calc-q-label">{question.label}</span>
        {question.type === 'choice' && (
          <CalcChoice options={question.options} value={value || ''} onChange={onChange} />
        )}
        {question.type === 'check' && (
          <>
            <p className="calc-q-hint">Cochez celles qui s'appliquent.</p>
            <CalcCheckGroup options={question.options} value={Array.isArray(value) ? value : []} onChange={onChange} />
          </>
        )}
        {question.type === 'text' && (
          <textarea
            className="calc-textarea"
            rows={question.rows || 3}
            placeholder={question.placeholder || ''}
            value={value || ''}
            onChange={e => onChange(e.target.value)}
          />
        )}
      </div>
    </div>
  );
}

/* ────────────────────────────────────────────────────────────
   Vue résultat — sections (Hero, Breakdown, Analyse, Solutions, CTA, Footer)
   ──────────────────────────────────────────────────────────── */

function CalcResultHero({ prenom, total, loading }) {
  return (
    <div className="calc-result-hero">
      <div className="calc-meta-mono">§ Diagnostic NeoFlow Immo</div>
      <h2 className="calc-result-headline">
        {prenom}, voici votre <em>diagnostic.</em>
      </h2>
      {loading || !total ? (
        <div className="calc-skeleton calc-skeleton-big" aria-hidden="true"></div>
      ) : (
        <>
          <p className="calc-big-number">{total.display_label || `${total.value_hours}h / semaine`}</p>
          <p className="calc-result-sub">
            perdues sur des tâches que vous pourriez <em>ne pas faire.</em>
          </p>
          <p className="calc-meta-mono calc-confidence">
            Estimation basée sur vos réponses
            {total.confidence ? ` · confiance : ${total.confidence}` : ''}
          </p>
        </>
      )}
    </div>
  );
}

function CalcResultBreakdown({ breakdown, loading }) {
  const [openIdx, setOpenIdx] = cUseState(null);
  const maxHours = cUseMemo(() => {
    if (!Array.isArray(breakdown) || breakdown.length === 0) return 0;
    return Math.max(...breakdown.map(b => b.value_hours || 0));
  }, [breakdown]);

  if (loading || !breakdown || breakdown.length === 0) {
    return (
      <div className="calc-result-breakdown">
        <div className="calc-section-h">Répartition</div>
        <div className="calc-skeleton-list">
          {[0, 1, 2].map(i => <div key={i} className="calc-skeleton calc-skeleton-row"></div>)}
        </div>
      </div>
    );
  }

  return (
    <div className="calc-result-breakdown">
      <div className="calc-section-h">Répartition</div>
      <ul className="calc-bd-list">
        {breakdown.map((item, i) => {
          const isOpen = openIdx === i;
          return (
            <li key={i} className={`calc-bd-row ${isOpen ? 'is-open' : ''}`}>
              <button
                type="button"
                className="calc-bd-head"
                aria-expanded={isOpen}
                onClick={() => setOpenIdx(isOpen ? null : i)}
              >
                <span className="calc-bd-cat">{item.category}</span>
                <span className="calc-bd-hours">{item.display_label || `≈ ${item.value_hours}h/sem`}</span>
              </button>
              <div className="calc-bd-bar" aria-hidden="true">
                <div
                  className="calc-bd-bar-fill"
                  style={{ width: `${calcBarPercent(item.value_hours, maxHours)}%`, animationDelay: `${i * 80}ms` }}
                ></div>
              </div>
              {isOpen && item.reasoning && (
                <p className="calc-bd-reasoning">{item.reasoning}</p>
              )}
            </li>
          );
        })}
      </ul>
    </div>
  );
}

function CalcResultAnalyse({ text, loading }) {
  return (
    <div className="calc-result-analyse">
      <h3 className="calc-section-title">Ce qu'on voit dans <em>votre situation.</em></h3>
      {loading || !text ? (
        <div className="calc-skeleton-list">
          <div className="calc-skeleton calc-skeleton-line"></div>
          <div className="calc-skeleton calc-skeleton-line"></div>
          <div className="calc-skeleton calc-skeleton-line calc-skeleton-short"></div>
        </div>
      ) : (
        <p className="calc-analyse-text">{text}</p>
      )}
    </div>
  );
}

function CalcComplexityTag({ level }) {
  const map = {
    low:    { label: 'Complexité faible',  cls: 'is-low' },
    medium: { label: 'Complexité moyenne', cls: 'is-medium' },
    high:   { label: 'Complexité élevée',  cls: 'is-high' },
  };
  const m = map[level] || { label: 'Complexité', cls: '' };
  return <span className={`calc-complexity-tag ${m.cls}`}>{m.label}</span>;
}

function CalcResultSolutions({ items, loading }) {
  if (loading || !items || items.length === 0) {
    return (
      <div className="calc-result-solutions">
        <h3 className="calc-section-title">Problèmes &amp; <em>solutions.</em></h3>
        <div className="calc-solutions-grid">
          {[0, 1].map(i => (
            <div key={i} className="calc-solution-card calc-skeleton-card">
              <div className="calc-skeleton calc-skeleton-line"></div>
              <div className="calc-skeleton calc-skeleton-line"></div>
              <div className="calc-skeleton calc-skeleton-line calc-skeleton-short"></div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  return (
    <div className="calc-result-solutions">
      <h3 className="calc-section-title">Problèmes &amp; <em>solutions.</em></h3>
      <div className="calc-solutions-grid">
        {items.map((it, i) => (
          <article
            key={i}
            className="calc-solution-card"
            style={{ animationDelay: `${i * 100}ms` }}
          >
            <div className="calc-sol-num">{String(i + 1).padStart(2, '0')}</div>
            <h4 className="calc-sol-title">{it.probleme}</h4>

            <div className="calc-sol-section calc-sol-market">
              <span className="calc-sol-tag">Sur le marché</span>
              <p>{it.ce_qui_existe_sur_le_marche}</p>
            </div>

            <div className="calc-sol-section calc-sol-neoflow">
              <span className="calc-sol-tag calc-sol-tag-neoflow">Ce qu'on construit pour vous</span>
              <p>{it.ce_que_neoflow_construit_pour_vous}</p>
            </div>

            <CalcComplexityTag level={it.complexite_estimee} />
          </article>
        ))}
      </div>
    </div>
  );
}

/* ────────────────────────────────────────────────────────────
   CTA — 4 variations selon fit_assessment (cf. spec § 7.2)
   ──────────────────────────────────────────────────────────── */

function CalcResultCTA({ cta, fit, setRoute, prenom }) {
  if (!cta || !fit) return null;

  const fitPilote = fit.pilote_neoflow_immo;
  const fitAgency = fit.neoflow_agency_custom;

  function handleAction(action, intent, place) {
    calcPosthog('calculateur_cta_clicked', { intent, place });
    // Mapping action -> route
    if (action === 'open_contact_form') {
      // intent demarrer_projet_immo → /immo/repondre, sinon /demarrer
      if (intent === 'demarrer_projet_immo') return setRoute('/immo/repondre');
      return setRoute('/demarrer');
    }
    if (action === 'open_calendar')         return setRoute('/immo/appel');
    if (action === 'redirect_agency_home')  return setRoute('/demarrer');
    if (action === 'thanks_only')           return setRoute('/immobilier');
    // fallback : page rejoindre immo
    return setRoute('/immo/repondre');
  }

  // Détermine titre + texte selon fit (spec § 7.2)
  let titreH = '';
  let texte = '';
  let showPrimary = true;
  let showSecondary = !!(cta.secondary && cta.secondary.label);

  if (fitPilote === 'good_fit') {
    titreH = <>Vous correspondez exactement à <em>ce qu'on cherche.</em></>;
    texte = "On construit des solutions sur mesure pour des agences comme la vôtre — à coût réduit pour les premiers pionniers.";
  } else if (fitPilote === 'maybe' || fitAgency === 'good_fit') {
    titreH = <>Votre profil est <em>intéressant</em> pour NeoFlow.</>;
    if (fitPilote === 'not_a_fit') {
      // sous-cas : pilote not_a_fit + agency good_fit
      titreH = <>On peut construire <em>ça pour vous.</em></>;
      texte = "Votre métier sort du périmètre immo, mais NeoFlow Agency fait exactement ce genre de solution sur mesure.";
      showSecondary = false;
    } else {
      texte = "Vos besoins sont clairs — pas forcément le programme pilote immo, mais on peut construire quelque chose sur mesure.";
    }
  } else {
    // tout en not_a_fit
    titreH = <>Merci pour <em>vos réponses.</em></>;
    texte = "À ce stade, pas de besoin évident sur lequel on pourrait construire quelque chose d'utile pour vous. Si ça change un jour, vous savez où nous trouver.";
    showPrimary = false;
    showSecondary = false;
  }

  return (
    <div className="calc-result-cta">
      <h3 className="calc-section-title">{titreH}</h3>
      <p className="calc-cta-text">{texte}</p>

      <div className="calc-cta-actions">
        {showPrimary && cta.primary && cta.primary.label && (
          <button
            type="button"
            className="calc-btn-primary"
            onClick={() => handleAction(cta.primary.action, cta.primary.intent, 'primary')}
          >
            <span>{cta.primary.label}</span>
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none">
              <path d="M1 5h12m0 0L9 1m4 4L9 9" stroke="currentColor" strokeWidth="1.4"/>
            </svg>
          </button>
        )}
        {showSecondary && cta.secondary && cta.secondary.label && (
          <button
            type="button"
            className="calc-btn-ghost"
            onClick={() => handleAction(cta.secondary.action, cta.secondary.intent, 'secondary')}
          >
            <span>{cta.secondary.label}</span>
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none">
              <path d="M1 5h12m0 0L9 1m4 4L9 9" stroke="currentColor" strokeWidth="1.2"/>
            </svg>
          </button>
        )}
        {!showPrimary && !showSecondary && (
          <a
            href="#/immobilier"
            className="calc-link-back"
            onClick={(e) => {
              e.preventDefault();
              calcPosthog('calculateur_cta_clicked', { intent: 'back_immo', place: 'link' });
              setRoute('/immobilier');
            }}
          >
            ← Retour à NeoFlow Immo
          </a>
        )}
      </div>
    </div>
  );
}

/* ────────────────────────────────────────────────────────────
   Vue résultat (orchestration)
   ──────────────────────────────────────────────────────────── */

function CalcResultView({ prenom, data, loading, error, onRetry, onRestart, setRoute }) {
  if (error) {
    return (
      <div className="calc-result calc-result-error">
        <div className="calc-meta-mono">§ Diagnostic NeoFlow Immo</div>
        <h2 className="calc-result-headline">
          {prenom ? `${prenom}, ` : ''}une petite tuile <em>technique.</em>
        </h2>
        <p className="calc-error-text">{error}</p>
        <div className="calc-cta-actions">
          <button type="button" className="calc-btn-primary" onClick={onRetry}>
            <span>Réessayer</span>
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none"><path d="M1 5h12m0 0L9 1m4 4L9 9" stroke="currentColor" strokeWidth="1.4"/></svg>
          </button>
          <button
            type="button"
            className="calc-btn-ghost"
            onClick={() => {
              calcPosthog('calculateur_cta_clicked', { intent: 'contact_direct', place: 'error' });
              setRoute('/immo/question');
            }}
          >
            <span>Nous contacter directement</span>
          </button>
        </div>
      </div>
    );
  }

  const total = data && data.time_lost ? data.time_lost.total : null;
  const breakdown = data && data.time_lost ? data.time_lost.breakdown : null;
  const analyse = data ? data.analyse_situation : null;
  const solutions = data ? data.problemes_solutions : null;
  const cta = data ? data.cta : null;
  const fit = data ? data.fit_assessment : null;

  return (
    <div className="calc-result">
      {loading && (
        <div className="calc-loading-indicator calc-meta-mono">
          <span className="calc-loading-dot" aria-hidden="true"></span>
          Analyse de votre situation en cours…
        </div>
      )}

      <CalcResultHero prenom={prenom} total={total} loading={loading && !total} />
      <CalcResultBreakdown breakdown={breakdown} loading={loading && !breakdown} />
      <CalcResultAnalyse text={analyse} loading={loading && !analyse} />
      <CalcResultSolutions items={solutions} loading={loading && !solutions} />

      {!loading && cta && fit && (
        <CalcResultCTA cta={cta} fit={fit} setRoute={setRoute} prenom={prenom} />
      )}

      <div className="calc-result-footer">
        <p className="calc-meta-mono">
          Diagnostic généré avec une IA propriétaire · Données traitées en Europe ·
          Vos réponses sont conservées pour améliorer le produit
        </p>
        {!loading && (
          <button type="button" className="calc-link-restart" onClick={onRestart}>
            Refaire un diagnostic
          </button>
        )}
      </div>
    </div>
  );
}

/* ────────────────────────────────────────────────────────────
   Composant principal — Calculateur
   ──────────────────────────────────────────────────────────── */

function Calculateur({ setRoute }) {
  /* ── State persisté ── */
  const initial = cUseMemo(() => {
    const saved = calcSafeLoadState();
    if (saved && saved.identity && saved.answers) return saved;
    return {
      step: 0, // 0 = identité, puis index 1..N pour les questions branche
      identity: { prenom: '', email: '', ville: '', role: '' },
      answers: {},
      startedAtMs: Date.now(),
    };
  }, []);

  const [step, setStep]         = cUseState(initial.step || 0);
  const [identity, setIdentity] = cUseState(initial.identity);
  const [answers, setAnswers]   = cUseState(initial.answers);
  const startedAtRef            = cUseRef(initial.startedAtMs || Date.now());

  // Phase : 'form' | 'result'
  const [phase, setPhase]       = cUseState('form');
  const [resultData, setResultData] = cUseState(null);
  const [loading, setLoading]   = cUseState(false);
  const [submitError, setSubmitError] = cUseState(null);

  // Pour le cleanup "abandoned" : on capture la dernière étape vue.
  const lastStepRef = cUseRef(0);
  const submittedRef = cUseRef(false);

  /* ── Calcul des étapes visibles selon la branche ── */
  const branch = identity.role ? CALC_BRANCHES[identity.role] : null;
  const branchQuestions = cUseMemo(() => {
    if (!branch) return [];
    return branch.questions.filter(q => !q.showIf || q.showIf(answers));
  }, [branch, answers]);
  const totalSteps = 1 + branchQuestions.length; // étape 1 = identité

  /* ── Persistance localStorage à chaque changement ── */
  cUseEffect(() => {
    calcSafeSaveState({
      step,
      identity,
      answers,
      startedAtMs: startedAtRef.current,
    });
    lastStepRef.current = step;
  }, [step, identity, answers]);

  /* ── PostHog : start au mount ── */
  cUseEffect(() => {
    calcPosthog('calculateur_start', { branche: branch ? branch.code : null });
    return () => {
      // Cleanup : si on quitte sans avoir submit, c'est un abandon
      if (!submittedRef.current && (lastStepRef.current > 0 || Object.keys(answers).length > 0 || identity.prenom)) {
        calcPosthog('calculateur_abandoned', {
          last_step: lastStepRef.current,
          branche: identity.role ? (CALC_BRANCHES[identity.role] && CALC_BRANCHES[identity.role].code) : null,
        });
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  /* ── Helpers state ── */
  function setAnswer(qid, value) {
    setAnswers(a => ({ ...a, [qid]: value }));
  }

  function canGoNext() {
    if (step === 0) return calcIdentityValid(identity);
    const q = branchQuestions[step - 1];
    if (!q) return false;
    return calcIsAnswered(q, answers[q.id]);
  }

  function goNext() {
    if (!canGoNext()) return;
    calcPosthog('calculateur_step_completed', {
      step: step + 1,
      branche: branch ? branch.code : null,
      is_identity: step === 0,
    });
    if (step < totalSteps - 1) {
      setStep(s => s + 1);
      // scroll top du form pour mobile
      try {
        const el = document.getElementById('calc-form-anchor');
        if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
      } catch (_) {}
    } else {
      submit();
    }
  }

  function goPrev() {
    if (step > 0) setStep(s => s - 1);
  }

  function restart() {
    calcClearState();
    setStep(0);
    setIdentity({ prenom: '', email: '', ville: '', role: '' });
    setAnswers({});
    setResultData(null);
    setSubmitError(null);
    setPhase('form');
    submittedRef.current = false;
    startedAtRef.current = Date.now();
    calcPosthog('calculateur_start', { restart: true });
  }

  /* ── Submit ── */
  async function submit() {
    if (loading) return;
    submittedRef.current = true;

    const branche = branch ? branch.code : null;
    const role = CALC_ROLES.find(r => r.id === identity.role);

    const payload = {
      submission: {
        timestamp_submit: new Date().toISOString(),
        branche,
        raw_answers: { ...answers },
        identity: {
          prenom: (identity.prenom || '').trim(),
          email:  (identity.email  || '').trim(),
          ville:  (identity.ville  || '').trim(),
          role:   identity.role,
          role_label: role ? role.label : null,
        },
        user_agent: typeof navigator !== 'undefined' ? navigator.userAgent : '',
        referrer: typeof document !== 'undefined' ? document.referrer : '',
        utm_source: calcGetUtmSource(),
        form_fill_duration_ms: Date.now() - (startedAtRef.current || Date.now()),
      },
    };

    calcPosthog('calculateur_submitted', { branche });

    // Bascule immédiate sur l'écran résultat
    setPhase('result');
    setLoading(true);
    setSubmitError(null);
    setResultData(null);

    let timeoutId = null;
    const controller = (typeof AbortController !== 'undefined') ? new AbortController() : null;
    const timeoutPromise = new Promise((_, reject) => {
      timeoutId = setTimeout(() => {
        if (controller) { try { controller.abort(); } catch (_) {} }
        reject(new Error('timeout'));
      }, CALC_TIMEOUT_MS);
    });

    try {
      const fetchPromise = fetch(CALC_WEBHOOK_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
        signal: controller ? controller.signal : undefined,
      });

      const response = await Promise.race([fetchPromise, timeoutPromise]);
      if (timeoutId) clearTimeout(timeoutId);

      if (!response || !response.ok) {
        throw new Error(response ? `HTTP ${response.status}` : 'no response');
      }

      const json = await response.json();

      // L'IA peut renvoyer le JSON soit "à plat" soit wrappé.
      let data = json;
      if (json && json.result && typeof json.result === 'object') data = json.result;
      if (json && json.data && typeof json.data === 'object')   data = json.data;

      if (!data || !data.time_lost || !data.cta || !data.fit_assessment) {
        throw new Error('JSON IA invalide');
      }

      setResultData(data);
      setLoading(false);
      calcPosthog('calculateur_result_displayed', { branche });
      // On vide le localStorage : le diagnostic est livré.
      calcClearState();
    } catch (e) {
      if (timeoutId) clearTimeout(timeoutId);
      setLoading(false);
      const msg = (e && e.message === 'timeout')
        ? "L'analyse prend trop de temps. Le serveur est peut-être surchargé."
        : "Une erreur est survenue pendant l'analyse de vos réponses.";
      setSubmitError(msg);
      calcPosthog('calculateur_result_error', { branche, error: e && e.message ? e.message : 'unknown' });
    }
  }

  /* ────────────── Render ────────────── */

  if (phase === 'result') {
    return (
      <section className="calc-section dark-section" id="calculateur" data-section="calculateur">
        <div className="wrap">
          <CalcResultView
            prenom={identity.prenom}
            data={resultData}
            loading={loading}
            error={submitError}
            onRetry={() => { setPhase('form'); setSubmitError(null); submit(); }}
            onRestart={restart}
            setRoute={setRoute}
          />
        </div>
      </section>
    );
  }

  // Phase : formulaire
  const isIdentity = step === 0;
  const currentQ = !isIdentity ? branchQuestions[step - 1] : null;

  return (
    <section className="calc-section dark-section" id="calculateur" data-section="calculateur">
      <div className="wrap calc-wrap">
        <div className="calc-head">
          <div className="calc-meta-mono">§ 05 · Calculateur Temps Perdu</div>
          <h2 className="calc-title">
            Combien d'heures vous perdez <em>chaque semaine ?</em>
          </h2>
          <p className="calc-sub">
            5 minutes de questions, un diagnostic IA personnalisé — chiffré, sans bullshit.
            On vous dit honnêtement si on peut vous aider, ou pas.
          </p>
        </div>

        <div id="calc-form-anchor" className="calc-form-anchor" aria-hidden="true"></div>

        <div className="calc-form-shell">
          <div className="calc-form-top">
            <div className="calc-meta-mono">
              Étape {step + 1} / {totalSteps}
              {branch && !isIdentity ? ` · Profil ${branch.label}` : ''}
            </div>
            <CalcProgress step={step} total={totalSteps} />
          </div>

          {isIdentity ? (
            <CalcIdentityStep identity={identity} setIdentity={setIdentity} />
          ) : (
            currentQ && (
              <CalcBranchQuestion
                question={currentQ}
                value={answers[currentQ.id]}
                onChange={(v) => setAnswer(currentQ.id, v)}
              />
            )
          )}

          <div className="calc-form-nav">
            <button
              type="button"
              className="calc-btn-primary"
              onClick={goNext}
              disabled={!canGoNext() || loading}
              aria-disabled={!canGoNext() || loading}
            >
              <span>{step === totalSteps - 1 ? 'Lancer mon diagnostic' : 'Suivant'}</span>
              <svg width="14" height="10" viewBox="0 0 14 10" fill="none">
                <path d="M1 5h12m0 0L9 1m4 4L9 9" stroke="currentColor" strokeWidth="1.4"/>
              </svg>
            </button>
            {step > 0 && (
              <button type="button" className="calc-btn-ghost" onClick={goPrev}>
                <span>Précédent</span>
              </button>
            )}
            {(step > 0 || identity.prenom) && (
              <button
                type="button"
                className="calc-link-restart"
                onClick={() => {
                  if (window.confirm('Vider vos réponses et recommencer ?')) restart();
                }}
              >
                Recommencer
              </button>
            )}
          </div>
        </div>
      </div>
    </section>
  );
}

/* Expose global */
window.Calculateur = Calculateur;
