// ============================================================
// Monarch — Socle partagé des simulateurs (window.MSC)
// Chargé AVANT les fichiers de simulateurs. Aucune dépendance externe.
// ============================================================

(function () {
  const { useState, useEffect, useRef } = React;

  const C = {
    blanc: "#FFFFFF", albatre: "#FAF9F6", encre: "#1B1D1C",
    ardoise: "#5B7C99", ardoiseF: "#3D5468",
    sauge: "#5C6F5C", saugeF: "#48584A",
    gris: "#737373", grisC: "#9A9A95", trait: "#E4E1DA"
  };
  const SERIF = "'Fraunces', Georgia, serif";
  const BODY = "'Archivo', system-ui, sans-serif";
  const CAL_LINK = "hugo-groslambert/diagnostic1h";
  const CAL_ORIGIN = "https://cal.eu";

  // ---- fiscalité partagée ----
  const IS_SEUIL = 42500;
  function IS(base) {
    const bas = Math.min(Math.max(base, 0), IS_SEUIL);
    const haut = Math.max(0, base - IS_SEUIL);
    return bas * 0.15 + haut * 0.25;
  }
  const flatTax = (m) => m * 0.314;

  // Barème progressif DMTG en ligne directe (par part, après abattement)
  const DMTG_TRANCHES = [
    [8072, 0.05], [12109, 0.10], [15932, 0.15],
    [552324, 0.20], [902838, 0.30], [1805677, 0.40], [Infinity, 0.45]
  ];
  function dmtg(baseTaxable) {
    let reste = Math.max(0, baseTaxable), prev = 0, tax = 0;
    for (const [plafond, taux] of DMTG_TRANCHES) {
      const part = Math.min(reste, plafond - prev);
      if (part <= 0) break;
      tax += part * taux;
      reste -= part; prev = plafond;
      if (reste <= 0) break;
    }
    return tax;
  }

  // ---- format ----
  const euro0 = new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR", maximumFractionDigits: 0 });
  const fmt = (n) => euro0.format(Math.round(n || 0));
  const pct = (n, b) => b > 0 ? Math.round((n / b) * 100) : 0;

  // ---- CountUp ----
  function useCountUp(target, run, duration) {
    const [val, setVal] = useState(0);
    useEffect(() => {
      if (!run) { setVal(0); return; }
      const d = duration || 1100; let raf, start;
      const ease = (t) => 1 - Math.pow(1 - t, 3);
      const tick = (ts) => { if (!start) start = ts; const p = Math.min(1, (ts - start) / d); setVal(target * ease(p)); if (p < 1) raf = requestAnimationFrame(tick); };
      raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf);
    }, [target, run, duration]);
    return val;
  }
  function CountEuro({ value, run, style }) { return <span style={style}>{fmt(useCountUp(value, run))}</span>; }

  // ---- styles partagés ----
  function injectCore() {
    if (document.getElementById("msc-styles")) return;
    const s = document.createElement("style");
    s.id = "msc-styles";
    s.textContent = `
      .msc-grid2 { display:grid; grid-template-columns:1fr 1fr; gap:22px; align-items:stretch; }
      .msc-inputs { display:grid; grid-template-columns:1fr 1fr; gap:24px 34px; }
      .msc-line { stroke-dasharray:760; stroke-dashoffset:760; transition:stroke-dashoffset 1s ease; }
      .msc-line.on { stroke-dashoffset:0; }
      .msc-soft { opacity:0; transition:opacity .8s ease; }
      .msc-soft.on { opacity:1; }
      .msc-slideup { opacity:0; transform:translateY(22px); transition:opacity .6s ease, transform .6s cubic-bezier(.2,.7,.3,1); }
      .msc-slideup.on { opacity:1; transform:none; }
      .msc-lockbar { transition: stroke-dashoffset 1.1s ease .2s; }
      @media (max-width:820px){ .msc-grid2{grid-template-columns:1fr !important;} .msc-inputs{grid-template-columns:1fr !important; gap:20px !important;} }
    `;
    document.head.appendChild(s);
  }

  // ---- atomes UI ----
  function Eyebrow({ children, color }) {
    return <span style={{ fontFamily: BODY, fontSize: 11.5, letterSpacing: "0.2em", textTransform: "uppercase", color: color || C.ardoise, fontWeight: 600 }}>{children}</span>;
  }
  function Label({ children }) {
    return <label style={{ fontFamily: BODY, fontSize: 12, letterSpacing: "0.12em", textTransform: "uppercase", color: C.ardoise, fontWeight: 600, display: "block", marginBottom: 10 }}>{children}</label>;
  }
  function MoneyInput({ value, onChange, min, max, step }) {
    return (
      <div>
        <div style={{ display: "flex", alignItems: "baseline", gap: 8, borderBottom: `2px solid ${C.encre}`, paddingBottom: 8 }}>
          <input type="text" inputMode="numeric" value={value === "" ? "" : Number(value).toLocaleString("fr-FR")}
            onChange={(e) => { const n = e.target.value.replace(/[^\d]/g, ""); onChange(n === "" ? "" : Number(n)); }}
            style={{ fontFamily: SERIF, fontSize: "clamp(26px,3.4vw,40px)", fontWeight: 500, color: C.encre, border: "none", background: "transparent", outline: "none", width: "100%", padding: 0 }} />
          <span style={{ fontFamily: SERIF, fontSize: "clamp(20px,2.6vw,30px)", color: C.ardoiseF }}>€</span>
        </div>
        {max != null &&
          <input type="range" min={min} max={max} step={step || 1000} value={Number(value) || 0} onChange={(e) => onChange(Number(e.target.value))}
            style={{ width: "100%", marginTop: 14, accentColor: C.sauge }} />}
      </div>);
  }
  function IntInput({ value, onChange, min, max }) {
    return (
      <div style={{ display: "inline-flex", border: `1px solid ${C.trait}`, background: C.blanc, alignItems: "stretch" }}>
        <button onClick={() => onChange(Math.max(min, (Number(value) || 0) - 1))} style={stepBtn}>−</button>
        <div style={{ minWidth: 64, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: SERIF, fontSize: 24, fontWeight: 500, color: C.encre }}>{value}</div>
        <button onClick={() => onChange(Math.min(max, (Number(value) || 0) + 1))} style={stepBtn}>+</button>
      </div>);
  }
  const stepBtn = { fontFamily: BODY, fontSize: 20, width: 46, border: "none", background: "transparent", color: C.encre, cursor: "pointer" };

  function Toggle({ options, value, onChange, full }) {
    return (
      <div style={{ display: "inline-flex", border: `1px solid ${C.trait}`, borderRadius: 2, overflow: "hidden", background: C.blanc, width: full ? "100%" : "auto" }}>
        {options.map((o) => {
          const on = o.id === value;
          return <button key={o.id} onClick={() => onChange(o.id)} style={{ flex: full ? 1 : "0 0 auto", fontFamily: BODY, fontSize: 14, fontWeight: 600, padding: "12px 16px", cursor: "pointer", border: "none", background: on ? C.encre : "transparent", color: on ? "#fff" : C.encre, transition: "background .2s" }}>{o.label}</button>;
        })}
      </div>);
  }

  // Enveloppe de section (cohérente avec le simulateur d'extraction)
  function Shell({ eyebrow, title, intro, children }) {
    return (
      <section style={{ background: C.blanc, padding: "16px 0 40px" }}>
        <div className="m-wrap" style={{ maxWidth: 1240, margin: "0 auto", padding: "0 32px" }}>
          <div style={{ maxWidth: "46em" }}>
            <Eyebrow>{eyebrow}</Eyebrow>
            <h2 style={{ fontFamily: SERIF, fontSize: "clamp(26px,3.4vw,42px)", fontWeight: 500, lineHeight: 1.08, letterSpacing: "-0.015em", margin: "14px 0 0" }}>{title}</h2>
            {intro && <p style={{ fontFamily: BODY, fontSize: 17, color: C.gris, lineHeight: 1.6, marginTop: 16, maxWidth: "36em" }}>{intro}</p>}
          </div>
          {children}
        </div>
      </section>);
  }

  function InputsCard({ children, onCompute, computing, busyLabel, label }) {
    return (
      <div style={{ marginTop: 36, border: `1px solid ${C.trait}`, background: C.albatre, padding: "clamp(24px,4vw,40px)" }}>
        <div className="msc-inputs">{children}</div>
        <div style={{ marginTop: 28 }}>
          <button onClick={onCompute} disabled={computing}
            style={{ fontFamily: BODY, fontSize: 15.5, fontWeight: 600, color: "#fff", background: C.sauge, border: "none", borderRadius: 2, padding: "16px 30px", cursor: computing ? "default" : "pointer", display: "inline-flex", alignItems: "center", gap: 10 }}>
            {computing ? (busyLabel || "Calcul en cours…") : (label || "Calculer l'impact")}{!computing && <span>→</span>}
          </button>
        </div>
      </div>);
  }

  // Encart doctrine — fond anthracite, apparition slide-up
  function Doctrine({ open, eyebrow, title, children, accent }) {
    return (
      <div className={"msc-slideup" + (open ? " on" : "")} style={{ marginTop: 22, background: C.encre, color: "#fff", padding: "clamp(26px,4vw,42px)", borderLeft: `3px solid ${accent || C.sauge}` }}>
        {eyebrow && <Eyebrow color={C.sauge}>{eyebrow}</Eyebrow>}
        <h3 style={{ fontFamily: SERIF, fontSize: "clamp(21px,2.6vw,30px)", fontWeight: 500, letterSpacing: "-0.01em", margin: eyebrow ? "12px 0 14px" : "0 0 14px", color: "#fff" }}>{title}</h3>
        <div style={{ fontFamily: BODY, fontSize: 15, color: "#cfd2cf", lineHeight: 1.7, maxWidth: "46em" }}>{children}</div>
      </div>);
  }

  // Alerte doctrinale claire (fond clair, bordure gauche)
  function Alert({ open, title, children }) {
    return (
      <div className={"msc-slideup" + (open ? " on" : "")} style={{ marginTop: 22, background: C.albatre, borderLeft: `3px solid ${C.encre}`, border: `1px solid ${C.trait}`, padding: "clamp(20px,3vw,30px)" }}>
        <div style={{ fontFamily: BODY, fontSize: 11.5, letterSpacing: "0.16em", textTransform: "uppercase", color: C.ardoise, fontWeight: 600, marginBottom: 8 }}>Vigilance juridique</div>
        <h3 style={{ fontFamily: SERIF, fontSize: "clamp(18px,2.2vw,24px)", fontWeight: 500, margin: "0 0 12px", letterSpacing: "-0.01em" }}>{title}</h3>
        <div style={{ fontFamily: BODY, fontSize: 14.5, color: "#2c2e2d", lineHeight: 1.7, maxWidth: "46em" }}>{children}</div>
      </div>);
  }

  // CTA + portail email (modale) -> ouvre Cal
  function CTAEmail({ note }) {
    const book = (e) => {
      if (window.Cal) { if (e) e.preventDefault(); window.Cal("modal", { calLink: CAL_LINK, config: { layout: "month_view" } }); }
    };
    return (
      <div style={{ marginTop: 30 }}>
        <a href={CAL_ORIGIN + "/" + CAL_LINK} onClick={book} target="_blank" rel="noopener noreferrer"
          data-cal-link={CAL_LINK} data-cal-origin={CAL_ORIGIN} data-cal-config='{"layout":"month_view"}'
          style={{ fontFamily: BODY, fontSize: 15.5, fontWeight: 600, color: "#fff", background: C.sauge, border: "none", borderRadius: 2, padding: "17px 30px", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 10, textDecoration: "none" }}>
          Réserver mon 1er rendez-vous offert <span>→</span>
        </a>
        {note && <p style={{ fontFamily: BODY, fontSize: 12.5, color: C.grisC, marginTop: 12 }}>{note}</p>}
      </div>);
  }

  // Hook : déclenche `reveal` après montage des résultats
  function useReveal(active, delay) {
    const [on, setOn] = useState(false);
    useEffect(() => { if (active) { const id = setTimeout(() => setOn(true), delay || 200); return () => clearTimeout(id); } else setOn(false); }, [active, delay]);
    return on;
  }

  // Jauge horizontale (valeur conservée vs perte hachurée)
  function Gauge({ segments, base, run, height }) {
    const [w, setW] = useState(false);
    useEffect(() => { if (run) { const id = setTimeout(() => setW(true), 60); return () => clearTimeout(id); } else setW(false); }, [run]);
    return (
      <div style={{ position: "relative", height: height || 16, borderRadius: 2, overflow: "hidden", background: C.albatre, border: `1px solid ${C.trait}`, display: "flex" }}>
        {segments.map((s, i) =>
          <div key={i} title={s.label} style={{
            height: "100%", width: w ? pct(s.value, base) + "%" : 0, transition: "width 1.1s cubic-bezier(.2,.7,.3,1)", transitionDelay: (i * 90) + "ms",
            background: s.keep ? (s.good ? C.saugeF : C.ardoiseF) : "transparent",
            backgroundColor: s.keep ? (s.good ? C.saugeF : C.ardoiseF) : "rgba(91,124,153,.10)",
            backgroundImage: s.keep ? "none" : "repeating-linear-gradient(135deg, rgba(91,124,153,.42) 0, rgba(91,124,153,.42) 1.5px, transparent 1.5px, transparent 6px)"
          }} />)}
      </div>);
  }

  function Stat({ label, value, run, color, sub, small }) {
    return (
      <div>
        <div style={{ fontFamily: BODY, fontSize: 12.5, color: C.gris, marginBottom: 6 }}>{label}</div>
        <CountEuro value={value} run={run} style={{ fontFamily: SERIF, fontSize: small ? "clamp(22px,2.8vw,30px)" : "clamp(28px,3.8vw,44px)", fontWeight: 500, color: color || C.encre, letterSpacing: "-0.01em", lineHeight: 1 }} />
        {sub && <div style={{ fontFamily: BODY, fontSize: 12.5, color: C.grisC, marginTop: 6 }}>{sub}</div>}
      </div>);
  }

  // ---- Capture de leads (email) ----
  const LEAD_KEY = "monarch.lead.email";
  const LEAD_FULL_KEY = "monarch.lead.full";
  function getLeadEmail() { try { return localStorage.getItem(LEAD_KEY) || ""; } catch (e) { return ""; } }
  function getLeadFull() { try { return JSON.parse(localStorage.getItem(LEAD_FULL_KEY) || "null"); } catch (e) { return null; } }
  function hasFullProfile() { const f = getLeadFull(); return !!(f && f.nom && f.prenom && f.telephone && f.email); }
  function leadCapture(info, source) {
    const data = typeof info === "string" ? { email: info } : (info || {});
    if (data.email) { try { localStorage.setItem(LEAD_KEY, data.email); } catch (e) {} }
    if (data.nom && data.prenom && data.telephone && data.email) {
      try { localStorage.setItem(LEAD_FULL_KEY, JSON.stringify({ nom: data.nom, prenom: data.prenom, telephone: data.telephone, email: data.email })); } catch (e) {}
    }
    try {
      fetch("lead.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ nom: data.nom || "", prenom: data.prenom || "", telephone: data.telephone || "", email: data.email || "", source: source || "" }) }).catch(() => {});
    } catch (e) {}
  }

  // Modale d'accès — `full` => nom/prénom/téléphone/email ; sinon email seul
  function LeadModal({ open, onUnlock, onClose, source, title, subtitle, cta, full }) {
    const saved = full ? (getLeadFull() || {}) : {};
    const [nom, setNom] = useState(saved.nom || "");
    const [prenom, setPrenom] = useState(saved.prenom || "");
    const [telephone, setTelephone] = useState(saved.telephone || "");
    const [email, setEmail] = useState(saved.email || getLeadEmail() || "");
    if (!open) return null;
    const submit = (e) => {
      e.preventDefault();
      if (!/.+@.+\..+/.test(email)) return;
      if (full && (!nom.trim() || !prenom.trim() || telephone.replace(/[^\d]/g, "").length < 8)) return;
      const payload = full
        ? { nom: nom.trim(), prenom: prenom.trim(), telephone: telephone.trim(), email: email.trim() }
        : { email: email.trim() };
      leadCapture(payload, source || "acces");
      onUnlock(email);
    };
    const field = { fontFamily: BODY, fontSize: 15, color: C.encre, background: C.blanc, border: `1px solid ${C.trait}`, borderRadius: 2, padding: "14px 14px", outline: "none", width: "100%" };
    return (
      <div onClick={() => onClose && onClose()} style={{ position: "fixed", inset: 0, zIndex: 300, display: "flex", alignItems: "center", justifyContent: "center", padding: 20, background: "rgba(244,242,238,.55)", backdropFilter: "blur(7px)", WebkitBackdropFilter: "blur(7px)" }}>
        <div onClick={(e) => e.stopPropagation()} style={{ position: "relative", background: C.blanc, maxWidth: 480, width: "100%", padding: "clamp(28px,5vw,44px)", borderTop: `3px solid ${C.sauge}`, boxShadow: "0 30px 80px -30px rgba(0,0,0,.4)" }}>
          {onClose &&
            <button onClick={onClose} aria-label="Fermer" style={{ position: "absolute", top: 14, right: 14, width: 34, height: 34, border: "none", background: "transparent", color: C.gris, fontSize: 22, lineHeight: 1, cursor: "pointer" }}>×</button>}
          <Eyebrow>Accès réservé</Eyebrow>
          <h3 style={{ fontFamily: SERIF, fontSize: "clamp(24px,3vw,32px)", fontWeight: 500, margin: "12px 0 10px", letterSpacing: "-0.015em" }}>{title || "Accédez aux simulateurs"}</h3>
          <p style={{ fontFamily: BODY, fontSize: 14.5, color: C.gris, lineHeight: 1.6, margin: "0 0 22px" }}>{subtitle || "Renseignez votre adresse professionnelle pour ouvrir l'ensemble des outils d'ingénierie patrimoniale."}</p>
          <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            {full &&
              <React.Fragment>
                <div style={{ display: "flex", gap: 12 }}>
                  <input type="text" required autoFocus value={prenom} onChange={(e) => setPrenom(e.target.value)} placeholder="Prénom" autoComplete="given-name" style={field} />
                  <input type="text" required value={nom} onChange={(e) => setNom(e.target.value)} placeholder="Nom" autoComplete="family-name" style={field} />
                </div>
                <input type="tel" required value={telephone} onChange={(e) => setTelephone(e.target.value)} placeholder="Téléphone" autoComplete="tel" style={field} />
              </React.Fragment>}
            <input type="email" required autoFocus={!full} value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Adresse e-mail" autoComplete="email" style={field} />
            <button type="submit" style={{ fontFamily: BODY, fontSize: 15, fontWeight: 600, color: "#fff", background: C.sauge, border: "none", borderRadius: 2, padding: "15px", cursor: "pointer" }}>{cta || "Accéder aux simulateurs"} →</button>
          </form>
          <p style={{ fontFamily: BODY, fontSize: 11.5, color: C.grisC, marginTop: 14, lineHeight: 1.5 }}>Confidentiel · vos données ne sont jamais cédées · vous pourrez vous désinscrire à tout moment.</p>
        </div>
      </div>);
  }

  // Bloc pédagogique « comment ça marche » (étapes simples)
  function Explainer({ title, steps }) {
    return (
      <div style={{ marginTop: 22, border: `1px solid ${C.trait}`, background: C.blanc, padding: "clamp(22px,3vw,32px)" }}>
        <Eyebrow>Comment ça marche</Eyebrow>
        <h3 style={{ fontFamily: SERIF, fontSize: "clamp(20px,2.4vw,28px)", fontWeight: 500, letterSpacing: "-0.01em", margin: "10px 0 22px" }}>{title || "En quelques mots"}</h3>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(220px,1fr))", gap: 22 }}>
          {steps.map((s, i) =>
            <div key={i} style={{ display: "grid", gridTemplateColumns: "30px 1fr", gap: 12, alignItems: "start" }}>
              <span style={{ fontFamily: SERIF, fontSize: 19, color: C.ardoise, lineHeight: 1.2 }}>{i + 1}</span>
              <div style={{ fontFamily: BODY, fontSize: 14, color: "#2c2e2d", lineHeight: 1.6 }}>{s}</div>
            </div>)}
        </div>
      </div>);
  }

  // Avantages / Inconvénients — présentation honnête
  function ProsCons({ open, pour, contre, note }) {
    const tick = (color) => <span style={{ flex: "0 0 auto", marginTop: 3, color, fontFamily: BODY, fontWeight: 700, fontSize: 13 }}>—</span>;
    const col = (titre, items, color, bg) => (
      <div style={{ background: bg, border: `1px solid ${C.trait}`, padding: "clamp(20px,3vw,28px)" }}>
        <div style={{ fontFamily: BODY, fontSize: 11.5, letterSpacing: "0.16em", textTransform: "uppercase", color: color, fontWeight: 600, marginBottom: 14 }}>{titre}</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {items.map((it, i) =>
            <div key={i} style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
              {tick(color)}
              <span style={{ fontFamily: BODY, fontSize: 14, color: "#2c2e2d", lineHeight: 1.55 }}>{it}</span>
            </div>)}
        </div>
      </div>);
    return (
      <div className={"msc-slideup" + (open ? " on" : "")} style={{ marginTop: 22 }}>
        <div style={{ fontFamily: BODY, fontSize: 11.5, letterSpacing: "0.18em", textTransform: "uppercase", color: C.ardoise, fontWeight: 600, marginBottom: 12 }}>En toute transparence</div>
        <div className="msc-grid2">
          {col("Avantages", pour, C.saugeF, C.albatre)}
          {col("Inconvénients & limites", contre, "#a23b3b", C.blanc)}
        </div>
        {note && <p style={{ fontFamily: BODY, fontSize: 12.5, color: C.grisC, lineHeight: 1.6, margin: "14px 0 0" }}>{note}</p>}
      </div>);
  }

  window.MSC = {
    C, SERIF, BODY, CAL_LINK, CAL_ORIGIN,
    IS, flatTax, dmtg, fmt, pct,
    useCountUp, CountEuro, injectCore, useReveal,
    Eyebrow, Label, MoneyInput, IntInput, Toggle, Shell, InputsCard, Doctrine, Alert, CTAEmail, Gauge, Stat, Explainer, ProsCons,
    getLeadEmail, leadCapture, LeadModal, getLeadFull, hasFullProfile
  };
})();
