/* =========================================================
   COMPOSANTS REACT / JSX — Christelle Genier Réflexologie
   Chargé avec : <script type="text/babel" src="...components.jsx">
   Auto-montage : tout élément <div data-component="NomDuComposant">
   est remplacé par le composant correspondant.
   ========================================================= */
const { useState, useEffect, useRef } = React;

/* ---------------------------------------------------------
   COUCHE DONNÉES — "base de données" des demandes de RDV
   Démo : persistance navigateur (localStorage) — TOUJOURS active,
   elle reste le filet de sécurité visible dans la page admin.

   ╔══════════════════════════════════════════════════════════╗
   ║  BRANCHEMENT GOOGLE SHEETS                                ║
   ║  Collez ci-dessous l'URL de votre script Google Apps     ║
   ║  Script (déployé en "application web"). Chaque demande    ║
   ║  sera alors ajoutée en nouvelle ligne dans votre feuille ║
   ║  Google Sheets, EN PLUS de la sauvegarde locale.         ║
   ║                                                          ║
   ║  Mode d'emploi pas-à-pas : voir la page admin.html       ║
   ║  (section « Recevoir les demandes dans Google Sheets »)  ║
   ║  ou le fichier google-apps-script.gs à la racine.        ║
   ╚══════════════════════════════════════════════════════════╝
   Laissez la chaîne vide tant que le script n'est pas déployé. */
window.CM_ENDPOINT = ""; // ← collez ici l'URL .../exec de votre Apps Script

const RdvStore = {
  KEY: 'cm_rdv_demandes',
  all(){ try { return JSON.parse(localStorage.getItem(this.KEY)) || []; } catch(e){ return []; } },
  add(rec){ const l = this.all(); l.unshift(rec); localStorage.setItem(this.KEY, JSON.stringify(l)); return rec; },
  clear(){ localStorage.removeItem(this.KEY); },
  async submit(data){
    const rec = Object.assign({}, data, {
      id: 'RDV-' + Date.now().toString(36).toUpperCase(),
      recu_le: new Date().toISOString(),
      statut: 'Nouvelle'
    });
    // 1) Envoi vers Google Sheets (si l'URL est renseignée).
    //    Requête "simple" (text/plain) + mode no-cors : pas de préflight,
    //    Apps Script reçoit le JSON dans e.postData.contents.
    if (window.CM_ENDPOINT){
      try {
        await fetch(window.CM_ENDPOINT, {
          method: 'POST',
          mode: 'no-cors',
          headers: { 'Content-Type': 'text/plain;charset=utf-8' },
          body: JSON.stringify(rec)
        });
      } catch(e){ console.warn('Envoi Google Sheets impossible, demande conservée en local.', e); }
    }
    // 2) Sauvegarde locale — toujours active (filet de sécurité, visible dans admin).
    this.add(rec);
    return rec;
  }
};
window.RdvStore = RdvStore;

const SEANCES = [
  'Réflexologie plantaire (30 min · 50€)',
  'Réflexologie plantaire énergétique (1h · 80€)',
  'Drainage lymphatique du corps · Renata França (1h15 · 120€)',
  'Drainage lymphatique des jambes (40 min · 60€)',
  'Drainage lymphatique du visage (30 min · 60€)',
  'Madérothérapie ciblée (45 min · 90€)',
  'Madérothérapie · corps complet (1h20 · 150€)',
  'Kobido · soin du visage (1h · 90€)',
  'Forfait (réflexologie, drainage ou Kobido)',
  'Autre / je ne sais pas encore'
];

/* ---------------------------------------------------------
   FORMULAIRE DE RÉSERVATION (connecté à RdvStore)
   --------------------------------------------------------- */
function BookingForm(props){
  const empty = { nom:'', tel:'', email:'', seance: SEANCES[0], message:'' };
  const [form, setForm] = useState(empty);
  const [errors, setErrors] = useState({});
  const [sending, setSending] = useState(false);
  const [done, setDone] = useState(false);

  const set = (k) => (e) => setForm(f => Object.assign({}, f, { [k]: e.target.value }));

  function validate(){
    const er = {};
    if(!form.nom.trim()) er.nom = 'Indiquez votre prénom et nom.';
    if(!/^[+0-9 ().-]{8,}$/.test(form.tel.trim())) er.tel = 'Numéro de téléphone non valide.';
    if(!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(form.email.trim())) er.email = 'Adresse email non valide — vérifiez le format.';
    return er;
  }

  async function onSubmit(e){
    e.preventDefault();
    const er = validate();
    setErrors(er);
    if(Object.keys(er).length){
      const first = ['nom','tel','email'].find(k => er[k]);
      const el = document.getElementById('f-'+first);
      if(el) el.focus();
      return;
    }
    setSending(true);
    await RdvStore.submit(form);
    setSending(false);
    setDone(true);
  }

  if(done){
    return (
      <div className="form-card">
        <div className="form-success">
          <div className="ico">✓</div>
          <h3>Votre demande est bien partie</h3>
          <p>Merci {form.nom.split(' ')[0]}. Je vous recontacte personnellement sous 24 h pour fixer votre rendez-vous.</p>
          <button className="btn btn-light" style={{marginTop:'22px'}} onClick={()=>{ setForm(empty); setDone(false); setErrors({}); }}>
            Envoyer une autre demande
          </button>
        </div>
      </div>
    );
  }

  const field = (k, label, type='text', placeholder='', extra={}) => (
    <div className={'field' + (errors[k] ? ' invalid' : '')}>
      <label htmlFor={'f-'+k}>{label}</label>
      <input id={'f-'+k} type={type} value={form[k]} onChange={set(k)} placeholder={placeholder}
             aria-invalid={errors[k] ? 'true' : 'false'} aria-describedby={errors[k] ? 'e-'+k : undefined} {...extra} />
      <span className="err" id={'e-'+k} role="alert">{errors[k]}</span>
    </div>
  );

  return (
    <form className="form-card" onSubmit={onSubmit} noValidate>
      <h3>{props.title || 'Demander un rendez-vous'}</h3>
      <p className="fc-sub">Réponse personnelle sous 24 h — sans engagement.</p>
      {field('nom', 'Votre prénom & nom', 'text', 'ex. Marie Lambert', {autoComplete:'name'})}
      <div className="form-row">
        {field('tel', 'Téléphone', 'tel', 'ex. 06 12 34 56 78', {autoComplete:'tel', inputMode:'tel'})}
        {field('email', 'Email', 'email', 'ex. marie@email.com', {autoComplete:'email', inputMode:'email', spellCheck:false, autoCapitalize:'none'})}
      </div>
      <div className="field">
        <label htmlFor="f-seance">Séance souhaitée</label>
        <select id="f-seance" value={form.seance} onChange={set('seance')}>
          {SEANCES.map(s => <option key={s} value={s}>{s}</option>)}
        </select>
      </div>
      <div className="field">
        <label htmlFor="f-message">Votre message (facultatif)</label>
        <textarea id="f-message" value={form.message} onChange={set('message')} placeholder="Disponibilités, questions…"></textarea>
      </div>
      <button type="submit" className="btn btn-primary" disabled={sending}>
        {sending ? 'Envoi…' : 'Envoyer ma demande'} <span className="btn-arrow">→</span>
      </button>
      <p className="form-note">Vos données restent confidentielles et ne servent qu'à vous recontacter.</p>
    </form>
  );
}

/* ---------------------------------------------------------
   COMPTEUR ANIMÉ
   --------------------------------------------------------- */
function StatCounter(props){
  const end = parseInt(props.end, 10) || 0;
  const suffix = props.suffix || '';
  const [val, setVal] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);

  useEffect(() => {
    const el = ref.current;
    if(!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(en => {
        if(en.isIntersecting && !started.current){
          started.current = true;
          const dur = 1500, t0 = performance.now();
          const tick = (now) => {
            const p = Math.min((now - t0) / dur, 1);
            setVal(Math.round((1 - Math.pow(1 - p, 3)) * end));
            if(p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold:0.6 });
    io.observe(el);
    return () => io.disconnect();
  }, [end]);

  return (
    <div className="chiffre" ref={ref}>
      <div className="n">{val}{suffix}</div>
      <div className="l">{props.label}</div>
    </div>
  );
}

/* ---------------------------------------------------------
   CARROUSEL DE TÉMOIGNAGES (auto + flèches + points + swipe)
   --------------------------------------------------------- */
const AVIS = [
  { t:"Les séances de réflexologie plantaire avec Christelle sont d'une qualité exceptionnelle : on en sort détendu et revivifié, et en plus elle vous permet de mieux comprendre ce qui se passe en vous, rien qu'en touchant vos pieds. Une expérience magique, que je recommande vivement.", n:"Claire M.", s:"Réflexologie plantaire", i:"C", c:"linear-gradient(145deg,#E0B8A6,#C49480)" },
  { t:"Le drainage lymphatique Renata França est incroyable ! Dès la 1ʳᵉ séance on ressent une légèreté et un boost d'énergie. Les manœuvres toniques et précises stimulent la circulation.", n:"Marianne", s:"Drainage lymphatique · Renata França", i:"M", c:"linear-gradient(145deg,#C49480,#B07D69)" },
  { t:"Christelle est vraiment très à l'écoute et très professionnelle. Je suis arrivée oppressée, stressée… et je suis ressortie complètement détendue et bien plus apaisée.", n:"Sophie M.", s:"Réflexologie plantaire", i:"S", c:"linear-gradient(145deg,#E0B8A6,#B07D69)" },
  { t:"Après des séances régulières de drainage lymphatique, j'ai constaté les effets : moins de cellulite, une peau plus ferme. Christelle est très pro, sympathique et agréable. Je recommande les yeux fermés.", n:"Elambert C.", s:"Drainage lymphatique", i:"E", c:"linear-gradient(145deg,#D4A898,#B07D69)" },
  { t:"J'ai adoré le soin réflexologie plantaire, du pur bonheur ! Merci Christelle, vous avez des doigts de fée !", n:"Stéphanie L.", s:"Réflexologie plantaire", i:"S", c:"linear-gradient(145deg,#E0B8A6,#C49480)" }
];

function TestimonialCarousel(){
  const [i, setI] = useState(0);
  const n = AVIS.length;
  const timer = useRef(null);
  const touch = useRef(0);

  const go = (d) => setI(prev => (prev + d + n) % n);

  useEffect(() => {
    timer.current = setInterval(() => setI(prev => (prev + 1) % n), 6000);
    return () => clearInterval(timer.current);
  }, [n]);
  const pause = () => clearInterval(timer.current);

  const a = AVIS[i];
  return (
    <div className="carousel" onMouseEnter={pause}
         onTouchStart={(e)=>{ touch.current = e.touches[0].clientX; pause(); }}
         onTouchEnd={(e)=>{ const d = e.changedTouches[0].clientX - touch.current; if(Math.abs(d)>40) go(d<0?1:-1); }}>
      <div className="carousel-track">
        <div className="carousel-slide" key={i} style={{animation:'heroIn .6s ease'}}>
          <div className="stars" aria-label="5 étoiles sur 5">★★★★★</div>
          <p className="carousel-quote">« {a.t} »</p>
          <div className="carousel-pers">
            <span className="avatar" style={{background:a.c}}>{a.i}</span>
            <div style={{textAlign:'left'}}>
              <div className="avis-nom">{a.n}</div>
              <div className="avis-meta">{a.s}</div>
            </div>
          </div>
        </div>
      </div>
      <div className="carousel-ctrl">
        <button className="carousel-arrow" aria-label="Précédent" onClick={()=>{ pause(); go(-1); }}>‹</button>
        {AVIS.map((_, k) => (
          <span key={k} className={'carousel-dot' + (k===i?' active':'')} onClick={()=>{ pause(); setI(k); }}></span>
        ))}
        <button className="carousel-arrow" aria-label="Suivant" onClick={()=>{ pause(); go(1); }}>›</button>
      </div>
    </div>
  );
}

/* ---------------------------------------------------------
   CARTE INTERACTIVE DES ZONES RÉFLEXES (illustratif)
   --------------------------------------------------------- */
const ZONES = [
  { num:'01', nom:'Tête & sinus', x:50, y:16, txt:"Le bout des orteils correspond à la tête. On y travaille les maux de tête, la concentration et la sphère ORL.", chips:['Maux de tête','Concentration','Sinus'] },
  { num:'02', nom:'Poitrine & respiration', x:44, y:36, txt:"La plante haute, sous les orteils, répond aux poumons et au cœur. Idéal pour relâcher la respiration et le stress.", chips:['Respiration','Stress','Détente'] },
  { num:'03', nom:'Système digestif', x:53, y:57, txt:"Le creux de la voûte plantaire correspond à l'estomac, au foie et aux intestins. On y régule la digestion.", chips:['Digestion','Foie','Transit'] },
  { num:'04', nom:'Bas du dos & bassin', x:50, y:80, txt:"Le talon répond au bas du dos, au bassin et au nerf sciatique. Précieux pour les tensions lombaires.", chips:['Lombaires','Sciatique','Bassin'] },
  { num:'05', nom:'Colonne vertébrale', x:33, y:52, txt:"Le bord interne du pied suit toute la colonne vertébrale, des cervicales au sacrum. Pour un dos apaisé.", chips:['Cervicales','Dos','Posture'] }
];

function ReflexologyMap(props){
  const [sel, setSel] = useState(0);
  const z = ZONES[sel];
  return (
    <div className="reflexo">
      <div className="reflexo-map">
        <img className="imgcover" src={props.img || 'assets/img/reflexo-foot.jpg'} alt="Cartographie des zones réflexes du pied" loading="lazy" />
        {ZONES.map((zone, k) => (
          <button key={k} className={'hotspot' + (k===sel?' active':'')} style={{left:zone.x+'%', top:zone.y+'%'}}
                  aria-label={zone.nom} onClick={()=>setSel(k)}></button>
        ))}
      </div>
      <div className="reflexo-info">
        <span className="zone-num">Zone {z.num}</span>
        <h3>{z.nom}</h3>
        <p>{z.txt}</p>
        <div className="reflexo-chips">
          {ZONES.map((zone, k) => (
            <button key={k} className={'reflexo-chip' + (k===sel?' active':'')} onClick={()=>setSel(k)}>{zone.nom}</button>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ---------------------------------------------------------
   TABLE ADMIN — visualisation de la "base de données"
   --------------------------------------------------------- */
function AdminTable(){
  const [rows, setRows] = useState([]);
  useEffect(() => { setRows(RdvStore.all()); }, []);

  const fmt = (iso) => { try { return new Date(iso).toLocaleString('fr-FR', {dateStyle:'short', timeStyle:'short'}); } catch(e){ return iso; } };

  function seed(){
    const demo = [
      { nom:'Marie Lambert', tel:'06 12 34 56 78', email:'marie.l@email.com', seance:SEANCES[0], message:'Disponible en fin de journée.' },
      { nom:'Sophie Renaud', tel:'07 88 22 11 90', email:'s.renaud@email.com', seance:SEANCES[3], message:'' }
    ];
    demo.forEach(d => RdvStore.submit(d));
    setTimeout(() => setRows(RdvStore.all()), 60);
  }
  function clearAll(){ if(confirm('Supprimer toutes les demandes enregistrées ?')){ RdvStore.clear(); setRows([]); } }

  return (
    <div>
      <div className="admin-stats">
        <div className="admin-stat"><div className="n">{rows.length}</div><div className="l">demande{rows.length>1?'s':''} reçue{rows.length>1?'s':''}</div></div>
        <div className="admin-stat"><div className="n">{rows.filter(r=>r.statut==='Nouvelle').length}</div><div className="l">nouvelle{rows.filter(r=>r.statut==='Nouvelle').length>1?'s':''}</div></div>
      </div>
      <div className="admin-head" style={{marginTop:0}}>
        <p style={{color:'var(--texte-doux)', maxWidth:'52ch'}}>Aperçu des demandes enregistrées via le formulaire. En production, ces données proviennent de votre base de données (voir note en bas de page).</p>
        <div className="admin-tools">
          <button className="btn-ghost" onClick={seed}>Ajouter des exemples</button>
          <button className="btn-ghost" onClick={clearAll}>Vider</button>
        </div>
      </div>
      {rows.length === 0 ? (
        <div className="admin-empty"><div className="ico">🗂️</div>Aucune demande pour l'instant.<br/>Remplissez le formulaire de la page Réserver, ou cliquez « Ajouter des exemples ».</div>
      ) : (
        <table className="admin-table">
          <thead><tr><th>Réf.</th><th>Reçu le</th><th>Cliente</th><th>Contact</th><th>Séance</th><th>Message</th><th>Statut</th></tr></thead>
          <tbody>
            {rows.map(r => (
              <tr key={r.id}>
                <td style={{fontFamily:'ui-monospace,monospace', fontSize:'12px'}}>{r.id}</td>
                <td>{fmt(r.recu_le)}</td>
                <td><strong>{r.nom}</strong></td>
                <td>{r.tel}<br/><span style={{color:'var(--texte-doux)', fontSize:'13px'}}>{r.email}</span></td>
                <td>{r.seance}</td>
                <td style={{maxWidth:'220px', whiteSpace:'normal', color:'var(--texte-doux)'}}>{r.message || '—'}</td>
                <td><span className="pill">{r.statut}</span></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </div>
  );
}

/* ---------------------------------------------------------
   AUTO-MONTAGE
   --------------------------------------------------------- */
const REGISTRY = { BookingForm, StatCounter, TestimonialCarousel, ReflexologyMap, AdminTable };

function mountComponents(){
  document.querySelectorAll('[data-component]').forEach(function(el){
    if(el.__mounted) return;
    const name = el.getAttribute('data-component');
    const Comp = REGISTRY[name];
    if(!Comp) return;
    const props = {};
    Array.prototype.forEach.call(el.attributes, function(a){
      if(a.name.indexOf('data-') === 0 && a.name !== 'data-component'){
        const key = a.name.slice(5).replace(/-([a-z])/g, (m,c)=>c.toUpperCase());
        props[key] = a.value;
      }
    });
    ReactDOM.createRoot(el).render(<Comp {...props} />);
    el.__mounted = true;
  });
}
mountComponents();
