/* app.boommaker.io — l'espace client du moteur de prospection (pack 390 €/mois).
 *
 * Qui entre ici : un client du pack, avec un seul email autorisé (table « Clients moteur » de
 * l'ERP), et Julia en admin, qui voit tous les comptes. Pas de mot de passe : un lien reçu par
 * email pose un cookie de session (voir api/espace.js).
 *
 * Trois vues : la connexion (ou l'ouverture d'un accès), l'accueil (où en est le compte, une
 * seule chose à faire), le parcours d'onboarding (onboarding.jsx). Julia a en plus la liste des
 * comptes et une fiche admin par compte.
 *
 * Règle d'expérience (Julia, 11/10/2026) : simple et agréable, une chose par écran, aucun
 * identifiant technique sous les yeux du client.
 */

const { useState, useEffect } = React;
const { Logo, ArrowUpRight, ThemeToggle, FooterApp } = window.BMUI;
const { Onboarding } = window.BMOnboarding;
const { PremierLot } = window.BMLot;

const CALENDLY = 'https://calendly.com/julia-boommaker/30min';

async function api(action, corps = {}) {
  const r = await fetch('/api/espace', {
    method: 'POST', credentials: 'same-origin',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ action, ...corps }),
  });
  const data = await r.json().catch(() => ({}));
  if (!r.ok) { const e = new Error(data.message || data.error || `Erreur ${r.status}`); e.status = r.status; e.data = data; throw e; }
  return data;
}

const dateLongue = (iso) => { if (!iso) return ''; try { return new Date(iso).toLocaleString('fr-FR', { dateStyle: 'full', timeStyle: 'short', timeZone: 'Europe/Paris' }); } catch { return iso; } };
const dateCourte = (iso) => { if (!iso) return ''; try { return new Date(iso).toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', timeZone: 'Europe/Paris' }); } catch { return iso; } };
const lireBrouillon = (c) => { try { return JSON.parse(c?.brouillon || '{}') || {}; } catch { return {}; } };

/* ---- Où en est le compte : une phrase, une action ------------------------------------ */

function etatDuCompte(c, brouillon) {
  const etape = Math.max(Number(c.etape) || 1, Number(brouillon?.etape) || 1);
  const fini = brouillon?.ecran === 'fin' || etape >= 5 && brouillon?.ecran === 'fin';
  switch (c.statut) {
    case 'Inscrit':
      return fini
        ? { ton: 'go', titre: 'Ton onboarding est prêt.', texte: 'Il ne reste qu\'à réserver la visio : on écrira tes premières séquences ensemble, sur de vrais prospects.', actions: [{ label: 'Réserver ma visio', href: CALENDLY, externe: true, principal: true }, { label: 'Relire mes réponses', vue: 'onboarding' }] }
        : etape > 1 || brouillon?.fiche?.client
          ? { ton: 'go', titre: 'Ton onboarding est en cours.', texte: `Chapitre ${etape} sur 5. Dix minutes suffisent pour finir, tout est enregistré au fur et à mesure.`, actions: [{ label: 'Continuer', vue: 'onboarding', principal: true }] }
          : { ton: 'go', titre: 'Bienvenue. On commence par toi.', texte: 'Cinq chapitres, une question par écran, dix minutes. Ton site fait l\'essentiel du travail : tu corriges au lieu de rédiger.', actions: [{ label: 'Commencer mon onboarding', vue: 'onboarding', principal: true }] };
    case 'Visio réservée':
      return { ton: 'go', titre: c.visio ? `Visio ${dateLongue(c.visio)}.` : 'Ta visio est réservée.', texte: fini ? 'Tes réponses sont prêtes. On se retrouve en visio pour écrire tes premières séquences.' : 'D\'ici là, termine ton onboarding : tout est enregistré au fur et à mesure.', actions: [{ label: fini ? 'Relire mes réponses' : 'Continuer mon onboarding', vue: 'onboarding', principal: !fini }] };
    case 'Premier lot en cours':
      return { ton: 'go', titre: 'Tes dix premières séquences sont en écriture.', texte: 'Compte une quinzaine de minutes. Tu recevras un email dès qu\'elles sont prêtes à relire.', actions: [{ label: 'Voir où ça en est', vue: 'lot' }] };
    case 'Lot à valider':
      return { ton: 'warn', titre: 'Dix séquences t\'attendent.', texte: 'La seule validation que tu feras : ensuite le moteur tourne seul. Lis, corrige ce qui ne sonne pas comme toi, écarte un prospect si besoin, puis lance.', actions: [{ label: 'Valider mon premier lot', vue: 'lot', principal: true }] };
    case 'Validé, à payer':
      return { ton: 'warn', titre: 'Il ne reste que le paiement pour lancer.', texte: 'Dès le paiement confirmé, on branche ta boîte mail et ton LinkedIn, et les premiers messages partent.', actions: [{ label: 'Payer et lancer', action: 'payer', principal: true }, { label: 'Revoir mon lot', vue: 'lot' }] };
    case 'Actif':
      return { ton: 'ok', titre: 'Ton moteur tourne.', texte: c.envoiDemarreLe ? `Envois démarrés le ${dateCourte(c.envoiDemarreLe)}. Les séquences sous 8/10 ne partent pas, tu n'as rien à valider.` : 'Les envois démarrent dès que ta boîte mail et ton LinkedIn sont connectés.', actions: [{ label: 'Voir mes réponses', bientot: true, principal: true }, { label: 'Gérer mon abonnement', action: 'portail' }] };
    case 'En pause':
      return { ton: 'warn', titre: 'Ton moteur est en pause.', texte: 'Rien ne part. Écris à Julia pour reprendre.', actions: [] };
    case 'Résilié':
      return { ton: 'warn', titre: 'Ton abonnement est résilié.', texte: `Tes données restent disponibles quatre-vingt-dix jours après le ${dateCourte(c.resilieLe)}.`, actions: [{ label: 'Reprendre mon abonnement', action: 'payer', principal: true }, { label: 'Exporter mes données', bientot: true }] };
    default:
      return { ton: '', titre: 'Bienvenue.', texte: '', actions: [] };
  }
}

/* ---- Composants ----------------------------------------------------------------------- */

const MENU_CLIENT = [
  ['accueil', 'Accueil'],
  ['onboarding', 'Onboarding'],
  ['lot', 'Premier lot'],
  ['prospects', 'Prospects', true],
  ['reponses', 'Réponses', true],
  ['rdv', 'Rendez-vous', true],
  ['reglages', 'Réglages', true],
];

/* La coque : une barre fine (logo à gauche, compte à droite) et un menu latéral, comme une
 * plateforme, pas comme le site vitrine. */
function Coque({ moi, vue, onVue, menu, children, titre }) {
  return (
    <div className="ap-shell">
      <header className="ap-top">
        <a href="/" className="ap-logo" aria-label="Boom Maker"><Logo /></a>
        <span className="ap-top-titre">Espace client</span>
        <div className="ap-top-droite">
          <a className="ap-top-lien" href={CALENDLY} target="_blank" rel="noopener">Besoin d'aide</a>
          <ThemeToggle />
          {moi ? <span className="ap-compte" title={moi.email}>{moi.role === 'admin' ? 'Julia · admin' : moi.email}</span> : null}
          {moi ? <a href="/api/espace?action=deconnexion" className="ap-top-lien">Déconnexion</a> : null}
        </div>
      </header>
      <div className={'ap-body' + (menu ? '' : ' sans-menu')}>
        {menu ? <aside className="ap-side">{menu}</aside> : null}
        <main className="ap-main">
          {titre ? <h1 className="ap-h1">{titre}</h1> : null}
          {children}
        </main>
      </div>
      <FooterApp />
    </div>
  );
}

function MenuClient({ vue, onVue }) {
  return (
    <nav className="ap-menu" aria-label="Mon espace">
      {MENU_CLIENT.map(([k, l, bientot]) => (
        <button key={k} type="button" className={'ap-menu-item' + (vue === k ? ' on' : '') + (bientot ? ' off' : '')} onClick={() => !bientot && onVue(k)} title={bientot ? 'Bientôt disponible' : undefined}>
          {l}{bientot ? <small>bientôt</small> : null}
        </button>
      ))}
    </nav>
  );
}

const Bouton = ({ a, onVue, onAction }) => {
  if (a.bientot) return <span className="btn" aria-disabled="true" title="Bientôt disponible">{a.label}</span>;
  if (a.action) return <button type="button" className={'btn' + (a.principal ? ' btn-glow' : '')} onClick={() => onAction && onAction(a.action)}>{a.label} {a.principal ? <ArrowUpRight /> : null}</button>;
  if (a.vue) return <button type="button" className={'btn' + (a.principal ? ' btn-glow' : '')} onClick={() => onVue(a.vue)}>{a.label} {a.principal ? <ArrowUpRight /> : null}</button>;
  return <a className={'btn' + (a.principal ? ' btn-glow' : '')} href={a.href} target={a.externe ? '_blank' : undefined} rel={a.externe ? 'noopener' : undefined}>{a.label} {a.principal ? <ArrowUpRight /> : null}</a>;
};

function Connexion({ message }) {
  const [mode, setMode] = useState('lien');
  const [email, setEmail] = useState('');
  const [entreprise, setEntreprise] = useState('');
  const [etat, setEtat] = useState('');
  const [erreur, setErreur] = useState('');

  async function envoyer(e) {
    e.preventDefault();
    setErreur(''); setEtat('envoi');
    try {
      await api(mode === 'lien' ? 'lien' : 'inscription', { email, entreprise });
      setEtat('envoye');
    } catch (err) {
      setEtat('');
      setErreur(err.data?.error === 'email_invalide' ? 'Cette adresse ne ressemble pas à un email.' : (err.message || "Impossible d'envoyer le lien pour le moment."));
    }
  }

  return (
    <div className="dg-card es-login">
      <h2>{mode === 'lien' ? 'Entrer dans mon espace' : 'Ouvrir mon espace'}</h2>
      {message ? <div className="es-note">{message}</div> : null}
      {etat === 'envoye' ? (
        <>
          <p>Ton lien est dans ta boîte, il est valable quinze minutes. Rien reçu au bout de deux minutes ? Regarde les indésirables.</p>
        </>
      ) : (
        <form onSubmit={envoyer}>
          <p style={{ marginBottom: 12 }}>{mode === 'lien' ? 'Pas de mot de passe : tape ton adresse, tu reçois un lien.' : 'Ton adresse et le nom de ton entreprise. Tu reçois un lien, et tu commences ton onboarding tout de suite.'}</p>
          {mode === 'inscription' ? <input className="ob-input" style={{ marginBottom: 10 }} required placeholder="Ton entreprise" value={entreprise} onChange={(e) => setEntreprise(e.target.value)} /> : null}
          <input type="email" required autoComplete="email" placeholder="ton@adresse.fr" value={email} onChange={(e) => setEmail(e.target.value)} />
          {erreur ? <div className="es-alerte" style={{ marginTop: 10 }}>{erreur}</div> : null}
          <div className="es-actions" style={{ marginTop: 12 }}>
            <button className="btn btn-glow" type="submit" disabled={etat === 'envoi' || !email}>{etat === 'envoi' ? 'Envoi…' : (mode === 'lien' ? 'Recevoir mon lien' : 'Ouvrir mon espace')} <ArrowUpRight /></button>
          </div>
          <p className="ob-skip" style={{ marginTop: 14 }}>
            {mode === 'lien'
              ? <>Pas encore d'accès ? <button type="button" className="ob-lien" onClick={() => setMode('inscription')}>Ouvre ton espace</button>.</>
              : <>Déjà un accès ? <button type="button" className="ob-lien" onClick={() => setMode('lien')}>Reçois ton lien</button>.</>}
          </p>
        </form>
      )}
    </div>
  );
}

function Accueil({ client, brouillon, onVue, onAction, message }) {
  const e = etatDuCompte(client, brouillon);
  const connexions = ['Validé, à payer', 'Actif', 'En pause'].includes(client.statut);
  return (
    <div className="es-accueil">
      {message ? <div className={message.ok ? 'es-note' : 'es-alerte'}>{message.texte}</div> : null}
      {client.alerte ? <div className="es-alerte">{client.alerte}</div> : null}
      <div className="dg-card es-card es-card-etat">
        <span className={'es-statut ' + e.ton}>{client.statut}</span>
        <h2>{e.titre}</h2>
        {e.texte ? <p>{e.texte}</p> : null}
        {e.actions.length ? <div className="es-actions">{e.actions.map((a) => <Bouton key={a.label} a={a} onVue={onVue} onAction={onAction} />)}</div> : null}
      </div>
      {connexions ? (
        <div className="dg-card es-card">
          <span className="es-k">Tes connexions</span>
          <div className="es-check"><ul>
            <li><span className={'es-dot ' + (client.dernierControle ? (client.boiteConnectee ? 'ok' : 'ko') : '')} />Boîte mail{client.dernierControle ? (client.boiteConnectee ? ' connectée' : ' à reconnecter') : ' : pas encore contrôlée'}</li>
            <li><span className={'es-dot ' + (client.dernierControle ? (client.linkedinConnecte ? 'ok' : 'ko') : '')} />LinkedIn{client.dernierControle ? (client.linkedinConnecte ? ' connecté' : ' à reconnecter') : ' : pas encore contrôlé'}</li>
          </ul></div>
        </div>
      ) : null}
      <p className="es-aide">Une question ? <a href={CALENDLY} target="_blank" rel="noopener">Prends un créneau avec Julia</a>.</p>
    </div>
  );
}

/* ---- La fiche admin d'un compte : tout ce que le client ne voit pas ------------------- */

function FicheAdmin({ c, onMaj }) {
  const [f, setF] = useState({});
  const [cle, setCle] = useState('');
  const [etat, setEtat] = useState('');
  const [erreur, setErreur] = useState('');
  useEffect(() => { setF({}); setCle(''); setEtat(''); setErreur(''); }, [c.id]);
  const v = (k) => (f[k] !== undefined ? f[k] : (c[k] ?? ''));
  const set = (k, val) => setF((x) => ({ ...x, [k]: val }));
  const enregistrer = async () => {
    setEtat('envoi'); setErreur('');
    try {
      const champs = { ...f };
      if (cle) champs.cleEmelia = cle;
      const r = await api('admin_maj', { client: c.id, champs });
      onMaj(r.client); setF({}); setCle(''); setEtat('ok');
    } catch (e) { setEtat(''); setErreur(e.message); }
  };
  const modifie = Object.keys(f).length > 0 || !!cle;
  const Ligne = ({ k, label, type = 'text', aide }) => (
    <div className="ob-field">
      <label>{label}</label>
      <input className="ob-input" type={type} value={type === 'date' && v(k) ? String(v(k)).slice(0, 10) : (type === 'datetime-local' && v(k) ? String(v(k)).slice(0, 16) : v(k))} onChange={(e) => set(k, e.target.value)} />
      {aide ? <small>{aide}</small> : null}
    </div>
  );
  return (
    <div className="dg-card es-card">
      <span className="es-k">Fiche admin</span>
      <h3>{c.nom}</h3>
      <div className="ob-grid2">
        <Ligne k="nom" label="Nom du compte" />
        <Ligne k="entreprise" label="Entreprise" />
        <Ligne k="email" label="Email d'accès" type="email" aide="Une seule adresse par compte." />
        <div className="ob-field"><label>Statut</label><select className="ob-input" value={v('statut')} onChange={(e) => set('statut', e.target.value)}>{['Inscrit', 'Visio réservée', 'Premier lot en cours', 'Lot à valider', 'Validé, à payer', 'Actif', 'En pause', 'Résilié'].map((s) => <option key={s}>{s}</option>)}</select></div>
        <div className="ob-field"><label>Environnement</label><select className="ob-input" value={v('environnement')} onChange={(e) => set('environnement', e.target.value)}><option>prod</option><option>test</option></select></div>
        <div className="ob-field"><label>Jour de tour</label><select className="ob-input" value={v('jourTour')} onChange={(e) => set('jourTour', e.target.value)}>{['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi'].map((s) => <option key={s}>{s}</option>)}</select></div>
        <Ligne k="baseAirtable" label="Base Airtable" aide="Duplique la base modèle, colle l'identifiant app…" />
        <Ligne k="visio" label="Visio" type="datetime-local" />
        <Ligne k="compteEmelia" label="Compte Emelia (email)" type="email" />
        <Ligne k="compteEmeliaCreeLe" label="Compte Emelia créé le" type="date" aide="Essai 7 jours sans carte : rappel à J+5." />
        <div className="ob-field"><label>Clé API Emelia</label><input className="ob-input" type="password" value={cle} onChange={(e) => setCle(e.target.value)} placeholder={c.cleEmeliaPosee ? 'enregistrée (chiffrée), coller pour remplacer' : 'coller la clé du compte du client'} autoComplete="off" /><small>Chiffrée à l'enregistrement, jamais réaffichée.</small></div>
        <Ligne k="campagneEmelia" label="Campagne Emelia (id)" />
        <Ligne k="envoiDemarreLe" label="Envoi démarré le" type="date" aide="Pilote la chauffe 15 → 35." />
        <div className="ob-field"><label>Carte posée sur le compte Emelia</label><label className="es-switch"><input type="checkbox" checked={!!(f.carteEmeliaPosee !== undefined ? f.carteEmeliaPosee : c.carteEmeliaPosee)} onChange={(e) => set('carteEmeliaPosee', e.target.checked)} /> oui</label></div>
      </div>
      <div className="ob-field"><label>Notes</label><textarea className="ob-input" rows={3} value={v('notes')} onChange={(e) => set('notes', e.target.value)} /></div>
      <dl className="es-kv">
        <dt>Stripe</dt><dd>{c.stripeSubscription || 'pas d\'abonnement'}{c.payeLe ? ` · payé le ${dateCourte(c.payeLe)}` : ''}</dd>
        <dt>Étape 6 débloquée</dt><dd>{c.etape6Le ? dateLongue(c.etape6Le) : 'non'}</dd>
        <dt>Lot validé</dt><dd>{c.lotValideLe ? dateLongue(c.lotValideLe) : 'non'}</dd>
        <dt>Dernière connexion</dt><dd>{c.derniereConnexion ? dateLongue(c.derniereConnexion) : 'jamais'}</dd>
        <dt>Créé le</dt><dd>{c.creeLe ? dateLongue(c.creeLe) : ''}</dd>
      </dl>
      {erreur ? <div className="es-alerte">{erreur}</div> : null}
      <div className="es-actions">
        <button type="button" className="btn btn-glow" onClick={enregistrer} disabled={!modifie || etat === 'envoi'}>{etat === 'envoi' ? 'Enregistrement…' : 'Enregistrer'} <ArrowUpRight /></button>
        {etat === 'ok' && !modifie ? <span className="ob-save ok">Enregistré</span> : null}
      </div>
    </div>
  );
}

function NouveauCompte({ onCree }) {
  const [ouvert, setOuvert] = useState(false);
  const [nom, setNom] = useState(''); const [email, setEmail] = useState(''); const [test, setTest] = useState(false);
  const [erreur, setErreur] = useState(''); const [envoi, setEnvoi] = useState(false);
  if (!ouvert) return <button type="button" className="ob-btn-ghost" onClick={() => setOuvert(true)}>+ Nouveau compte</button>;
  const creer = async () => {
    setEnvoi(true); setErreur('');
    try { const r = await api('creer', { nom, email, environnement: test ? 'test' : 'prod' }); onCree(r.client); setOuvert(false); setNom(''); setEmail(''); }
    catch (e) { setErreur(e.message); } finally { setEnvoi(false); }
  };
  return (
    <div className="dg-card es-card" style={{ padding: 16 }}>
      <input className="ob-input" placeholder="Nom du compte" value={nom} onChange={(e) => setNom(e.target.value)} />
      <input className="ob-input" type="email" placeholder="Email d'accès (facultatif)" value={email} onChange={(e) => setEmail(e.target.value)} />
      <label className="es-switch"><input type="checkbox" checked={test} onChange={(e) => setTest(e.target.checked)} /> compte de test</label>
      {erreur ? <div className="es-alerte">{erreur}</div> : null}
      <div className="es-actions"><button type="button" className="btn btn-glow" onClick={creer} disabled={!nom || envoi}>Créer</button><button type="button" className="ob-btn-ghost" onClick={() => setOuvert(false)}>Annuler</button></div>
    </div>
  );
}

function Admin({ moi, recharger, onMajClient, onglet, setOnglet, onAction, message }) {
  const client = moi.client;
  const brouillon = lireBrouillon(client);
  if (!client) {
    return (
      <div className="dg-card es-card">
        <span className="es-k">Pilotage</span>
        <h2>{moi.clients.length} compte{moi.clients.length > 1 ? 's' : ''}</h2>
        <p>Choisis un compte dans le menu. La page de pilotage (alertes, actions à faire, coûts) arrive ici.</p>
      </div>
    );
  }
  return (
    <>
      <div className="es-onglets">
        {[['client', 'Vue client'], ['parcours', 'Parcours'], ['lot', 'Premier lot'], ['fiche', 'Fiche admin']].map(([k, l]) => (
          <button key={k} type="button" className={onglet === k ? 'on' : ''} onClick={() => setOnglet(k)}>{l}</button>
        ))}
      </div>
      {onglet === 'client' ? <p className="ap-note">Exactement ce que ce client voit en arrivant sur son espace. Il ne voit ni le parcours en mode admin, ni la fiche admin.</p> : null}
      {onglet === 'client' ? <Accueil client={client} brouillon={brouillon} onVue={(v) => setOnglet(v === 'lot' ? 'lot' : 'parcours')} onAction={onAction} message={message} /> : null}
      {onglet === 'parcours' ? <Onboarding key={client.id} compte={client} brouillon={brouillon} admin onSortie={() => setOnglet('client')} onChangement={() => {}} /> : null}
      {onglet === 'lot' ? <PremierLot key={client.id} compte={client} admin onStatut={(st) => onMajClient({ ...client, statut: st })} onPayer={() => onAction('payer')} /> : null}
      {onglet === 'fiche' ? <FicheAdmin c={client} onMaj={(c) => onMajClient(c)} /> : null}
    </>
  );
}

function MenuAdmin({ moi, choisir, onCree }) {
  return (
    <nav className="ap-menu" aria-label="Comptes">
      <span className="ap-menu-titre">Comptes</span>
      {moi.clients.map((c) => (
        <button key={c.id} type="button" className={'ap-menu-item' + (c.id === moi.client?.id ? ' on' : '')} onClick={() => choisir(c.id)}>
          <span className={'es-dot ' + (c.alerte ? 'ko' : c.statut === 'Actif' ? 'ok' : '')} />
          <span className="ap-menu-nom">{c.nom}<small>{c.statut}{c.environnement === 'test' ? ' · test' : ''}</small></span>
        </button>
      ))}
      <NouveauCompte onCree={onCree} />
    </nav>
  );
}

/* ---- La page ------------------------------------------------------------------------- */

function App() {
  const [moi, setMoi] = useState(null);
  const [chargement, setChargement] = useState(true);
  const [erreur, setErreur] = useState('');
  const [vue, setVue] = useState('accueil');
  const [onglet, setOnglet] = useState('client');
  const [message, setMessage] = useState(null);
  const params = new URLSearchParams(location.search);
  const messageLien = { perime: 'Ce lien a expiré ou a déjà servi. Demande-en un nouveau.', inconnu: "Cette adresse n'a plus d'accès. Vérifie avec Julia." }[params.get('lien')] || '';

  // Retour de Stripe : on confirme la session sans attendre le webhook, puis on nettoie l'adresse.
  useEffect(() => {
    const p = params.get('paiement');
    if (!p) return;
    history.replaceState(null, '', '/');
    if (p === 'annule') { setMessage({ ok: false, texte: 'Paiement annulé. Ton lot reste validé, tu peux payer quand tu veux.' }); return; }
    const sid = params.get('session');
    (async () => {
      try {
        const r = await api('paiement_statut', { session: sid, client: moi?.role === 'admin' ? moi.client?.id : undefined });
        setMessage(r.ok ? { ok: true, texte: 'Paiement confirmé. Ton moteur est actif : on branche ta boîte mail et ton LinkedIn, et les envois démarrent.' } : { ok: false, texte: 'Paiement en cours de confirmation. Recharge la page dans une minute.' });
        charger();
      } catch (e) { setMessage({ ok: false, texte: e.message }); }
    })();
  }, []);

  const action = async (quoi) => {
    setMessage(null);
    try {
      if (quoi === 'payer') {
        const r = await api('paiement', { client: moi?.role === 'admin' ? moi.client?.id : undefined });
        if (r.url) window.location.href = r.url;
      } else if (quoi === 'portail') {
        const r = await api('portail', { client: moi?.role === 'admin' ? moi.client?.id : undefined });
        if (r.url) window.location.href = r.url;
      }
    } catch (e) { setMessage({ ok: false, texte: e.message }); }
  };

  async function charger(clientId) {
    setErreur('');
    try { setMoi(await api('moi', clientId ? { client: clientId } : {})); }
    catch (e) { if (e.status === 401) setMoi(null); else setErreur(e.message); }
    finally { setChargement(false); }
  }
  useEffect(() => { charger(); }, []);

  const onMajClient = (c, ajout) => setMoi((m) => ({
    ...m,
    client: m.client?.id === c.id || ajout ? c : m.client,
    clients: ajout ? [...m.clients, c].sort((a, b) => a.nom.localeCompare(b.nom, 'fr')) : m.clients.map((x) => (x.id === c.id ? c : x)),
  }));

  const client = moi?.role === 'client' ? moi.client : null;
  const admin = moi?.role === 'admin';
  const titre = admin ? (moi.client ? moi.client.nom : 'Pilotage') : client ? (vue === 'onboarding' ? 'Mon onboarding' : vue === 'lot' ? 'Mon premier lot' : `Bonjour${client.entreprise ? ', ' + client.entreprise : ''}.`) : null;

  const contenu = () => {
    if (erreur) return <div className="es-alerte">{erreur}</div>;
    if (chargement) return <p style={{ color: 'var(--mute)' }}>Chargement…</p>;
    if (!moi) return <Connexion message={messageLien} />;
    if (admin) return <Admin moi={moi} recharger={charger} onMajClient={onMajClient} onglet={onglet} setOnglet={setOnglet} onAction={action} message={message} />;
    if (vue === 'lot') return <PremierLot compte={client} admin={false} onStatut={(st) => setMoi((m) => ({ ...m, client: { ...m.client, statut: st } }))} onPayer={() => action('payer')} />;
    if (vue === 'onboarding') return <Onboarding compte={client} brouillon={moi.brouillon || {}} admin={false} onSortie={() => { setVue('accueil'); charger(); }} onChangement={(b) => setMoi((m) => ({ ...m, brouillon: b }))} />;
    return <Accueil client={client} brouillon={moi.brouillon || {}} onVue={setVue} onAction={action} message={message} />;
  };

  const menu = !moi ? null : admin
    ? <MenuAdmin moi={moi} choisir={(id) => { setOnglet('client'); charger(id); }} onCree={(c) => { onMajClient(c, true); setOnglet('fiche'); charger(c.id); }} />
    : <MenuClient vue={vue} onVue={setVue} />;

  return (
    <Coque moi={moi} vue={vue} onVue={setVue} menu={menu} titre={titre}>
      {contenu()}
    </Coque>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
