// Botman My - Inbox WhatsApp (proxy api.botman.ch → Vocal)
const { useState, useEffect, useCallback, useRef, createContext, useContext } = React;

const CONFIG = {
  API_URL: (() => {
    const p = new URLSearchParams(location.search);
    if (p.get('api')) return p.get('api').replace(/\/$/, '');
    if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
      return 'http://127.0.0.1:8787'; // wrangler dev ch.botman.api
    }
    return 'https://ch-botman-api.yannick-zoller.workers.dev';
  })(),
  APP_URL: 'https://app.botman.ch',
  SITE_URL: 'https://botman.ch',
};

const STORAGE_TOKEN = 'botman_token';
const STORAGE_USER = 'botman_user';

// ==================== API ====================
const api = {
  token: null,
  async req(path, options = {}) {
    const headers = { 'Content-Type': 'application/json', ...options.headers };
    if (this.token) headers.Authorization = `Bearer ${this.token}`;
    const resp = await fetch(`${CONFIG.API_URL}${path}`, { ...options, headers });
    return resp.json();
  },
  get: (p) => api.req(p),
  post: (p, b) => api.req(p, { method: 'POST', body: JSON.stringify(b) }),
};

// ==================== CONTEXT ====================
const AppCtx = createContext(null);
const useApp = () => useContext(AppCtx);

const Icons = {
  Chat: () => <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.435 9.884-9.884 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>,
  Template: () => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>,
  Stats: () => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M18 20V10M12 20V4M6 20v-6"/></svg>,
  Phone: () => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z"/></svg>,
  External: () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3"/></svg>,
  Line: () => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 4h4l2 5-2.5 1.5a11 11 0 005 5L15 15l5 2v4a2 2 0 01-2 2A16 16 0 013 6a2 2 0 012-2z"/></svg>,
  Refresh: () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/></svg>,
};

const SENDER_STATUS_META = {
  PENDING:   { label: 'En préparation', cls: 'status-gray' },
  CREATING:  { label: 'Création…',      cls: 'status-info' },
  VERIFYING: { label: 'Vérification',   cls: 'status-warn' },
  ONLINE:    { label: 'Actif',          cls: 'status-ok' },
  ERRORED:   { label: 'Erreur',         cls: 'status-err' },
  OFFLINE:   { label: 'Hors-ligne',     cls: 'status-gray' },
};

function Toast({ msg, type, onDone }) {
  useEffect(() => { const t = setTimeout(onDone, 3500); return () => clearTimeout(t); }, [onDone]);
  return <div className={`toast ${type || ''}`}>{msg}</div>;
}

// ==================== AUTH ====================
function AuthScreen({ onLogin }) {
  const [step, setStep] = useState('email');
  const [email, setEmail] = useState('');
  const [code, setCode] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  useEffect(() => {
    const p = new URLSearchParams(location.search);
    const e = p.get('email');
    const c = p.get('code');
    if (e && c) {
      setEmail(e);
      setLoading(true);
      fetch(`${CONFIG.API_URL}/auth/verify-code`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: e.toLowerCase(), code: c }),
      })
        .then(r => r.json())
        .then(data => {
          if (data.success && data.token) {
            history.replaceState({}, '', location.pathname);
            onLogin(data.token, data.user);
          } else setError(data.error || 'Lien expiré');
        })
        .catch(() => setError('Erreur réseau'))
        .finally(() => setLoading(false));
    } else if (e) {
      setEmail(e);
      setStep('code');
    }
  }, []);

  const requestCode = async () => {
    if (!email.includes('@')) { setError('Email invalide'); return; }
    setLoading(true); setError('');
    try {
      const r = await fetch(`${CONFIG.API_URL}/auth/request-code`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.toLowerCase().trim() }),
      }).then(x => x.json());
      if (r.success) setStep('code');
      else setError(r.error || 'Erreur envoi');
    } catch { setError('Erreur réseau'); }
    finally { setLoading(false); }
  };

  const verify = async () => {
    setLoading(true); setError('');
    try {
      const r = await fetch(`${CONFIG.API_URL}/auth/verify-code`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.toLowerCase().trim(), code: code.trim() }),
      }).then(x => x.json());
      if (r.success && r.token) onLogin(r.token, r.user);
      else setError(r.error || 'Code invalide');
    } catch { setError('Erreur réseau'); }
    finally { setLoading(false); }
  };

  return (
    <div className="auth-screen">
      <div className="auth-card">
        <div className="auth-logo">
          <div className="auth-logo-icon"><Icons.Chat /></div>
          <span>Botman</span>
        </div>
        <p className="auth-tagline">
          {step === 'email'
            ? 'Connectez-vous pour gérer vos conversations WhatsApp.'
            : 'Entrez le code reçu par email.'}
        </p>
        {error && <p style={{ color: 'var(--danger)', fontSize: '0.85rem', marginBottom: '0.75rem' }}>{error}</p>}
        {step === 'email' ? (
          <>
            <input className="auth-input" type="email" placeholder="votre@email.ch" value={email}
              onChange={e => setEmail(e.target.value)} onKeyDown={e => e.key === 'Enter' && requestCode()} />
            <button className="btn btn-wa" disabled={loading} onClick={requestCode}>
              {loading ? 'Envoi…' : 'Recevoir le code'}
            </button>
          </>
        ) : (
          <>
            <input className="auth-input" type="text" inputMode="numeric" placeholder="Code à 6 chiffres" value={code}
              onChange={e => setCode(e.target.value)} onKeyDown={e => e.key === 'Enter' && verify()} />
            <button className="btn btn-wa" disabled={loading} onClick={verify}>
              {loading ? 'Vérification…' : 'Se connecter'}
            </button>
            <button className="btn btn-ghost" style={{ width: '100%', marginTop: '0.5rem' }}
              onClick={() => { setStep('email'); setCode(''); setError(''); }}>
              Changer d'email
            </button>
          </>
        )}
        <p style={{ fontSize: '0.75rem', color: 'var(--text-soft)', marginTop: '1.25rem', textAlign: 'center' }}>
          WhatsApp Business API
        </p>
      </div>
    </div>
  );
}

// ==================== INBOX ====================
function fmtTime(s) {
  if (!s) return '';
  try {
    const d = new Date(s.endsWith('Z') ? s : s + 'Z');
    const today = new Date();
    return d.toDateString() === today.toDateString()
      ? d.toLocaleTimeString('fr-CH', { hour: '2-digit', minute: '2-digit' })
      : d.toLocaleString('fr-CH', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
  } catch { return s; }
}

function statusIcon(st) {
  if (st === 'read') return '✓✓';
  if (st === 'delivered') return '✓✓';
  if (st === 'sent') return '✓';
  if (st === 'failed') return '✗';
  return '';
}

function InboxView() {
  const { notify } = useApp();
  const [conversations, setConversations] = useState([]);
  const [loading, setLoading] = useState(true);
  const [selectedId, setSelectedId] = useState(null);
  const [messages, setMessages] = useState([]);
  const [selected, setSelected] = useState(null);
  const [totals, setTotals] = useState(null);
  const [draft, setDraft] = useState('');
  const [sending, setSending] = useState(false);
  const scrollRef = useRef(null);
  const [mobileShowThread, setMobileShowThread] = useState(false);

  const loadConversations = useCallback(async (silent) => {
    if (!silent) setLoading(true);
    try {
      const r = await api.get('/conversations');
      if (r.error) { if (!silent) notify(r.error, 'error'); return; }
      setConversations(r.conversations || []);
      if (!selectedId && r.conversations?.length) setSelectedId(r.conversations[0].id);
    } catch { if (!silent) notify('Erreur chargement', 'error'); }
    finally { if (!silent) setLoading(false); }
  }, [notify, selectedId]);

  const loadMessages = useCallback(async (convId, silent) => {
    if (!convId) return;
    try {
      const r = await api.get(`/conversations/${convId}/messages`);
      if (r.error) { if (!silent) notify(r.error, 'error'); return; }
      setMessages(r.messages || []);
      setSelected(r.conversation || null);
      setTotals(r.totals || null);
      if (!silent) setTimeout(() => { if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight; }, 50);
    } catch { if (!silent) notify('Erreur messages', 'error'); }
  }, [notify]);

  useEffect(() => { loadConversations(); }, []);
  useEffect(() => { if (selectedId) loadMessages(selectedId); }, [selectedId]);
  useEffect(() => {
    const id = setInterval(() => {
      loadConversations(true);
      if (selectedId) loadMessages(selectedId, true);
    }, 12000);
    return () => clearInterval(id);
  }, [selectedId, loadConversations, loadMessages]);

  const sendReply = async () => {
    const text = draft.trim();
    if (!text || !selectedId) return;
    setSending(true);
    try {
      const r = await api.post(`/conversations/${selectedId}/reply`, { body: text, take_over: 1 });
      if (r.error) { notify(r.error, 'error'); return; }
      setDraft('');
      await loadMessages(selectedId);
      await loadConversations(true);
    } catch { notify('Erreur envoi', 'error'); }
    finally { setSending(false); }
  };

  const toggleBot = async (enabled) => {
    if (!selectedId) return;
    const r = await api.post(`/conversations/${selectedId}/bot`, { enabled: enabled ? 1 : 0 });
    if (r.error) { notify(r.error, 'error'); return; }
    setSelected(s => s ? { ...s, bot_enabled: enabled ? 1 : 0 } : s);
    notify(enabled ? 'Bot réactivé' : 'Vous avez pris la main');
  };

  const pickConv = (id) => {
    setSelectedId(id);
    setMobileShowThread(true);
  };

  return (
    <div className="inbox">
      <div className={`panel inbox-list ${mobileShowThread ? 'hidden-mobile' : ''}`}>
        <div className="panel-head">
          <strong>Conversations</strong>
          <button className="btn btn-sm btn-outline" onClick={() => loadConversations()}>↻</button>
        </div>
        <div className="panel-scroll">
          {loading && <div className="empty-state">Chargement…</div>}
          {!loading && conversations.length === 0 && (
            <div className="empty-state">
              Aucune conversation. Quand un client vous écrira sur WhatsApp, elle apparaîtra ici.
            </div>
          )}
          {conversations.map(c => (
            <div key={c.id}
              className={`conv-item ${selectedId === c.id ? 'active' : ''}`}
              onClick={() => pickConv(c.id)}>
              <div className="conv-top">
                <span className="conv-name">{c.contact_name || c.contact_number}</span>
                <span className="conv-time">{fmtTime(c.last_message_at)}</span>
              </div>
              <div className="conv-preview">
                {c.last_direction === 'outbound' ? '→ ' : ''}{c.last_message_body || '(média)'}
              </div>
              <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '0.25rem', fontSize: '0.72rem', color: 'var(--text-soft)' }}>
                <span>{c.line_label || c.line_phone}</span>
                {c.unread_count > 0 && <span className="badge-unread">{c.unread_count}</span>}
                {c.bot_enabled === 0 && <span style={{ color: '#f59e0b' }}>· humain</span>}
              </div>
            </div>
          ))}
        </div>
      </div>

      <div className={`panel ${!mobileShowThread && !selected ? '' : ''} inbox-thread ${!mobileShowThread && window.innerWidth < 768 && !selected ? 'hidden-mobile' : ''}`} style={{ borderRight: 0, flex: 1 }}>
        {!selected && (
          <div className="empty-state" style={{ margin: 'auto' }}>
            Sélectionnez une conversation pour lire et répondre.
          </div>
        )}
        {selected && (
          <>
            <div className="panel-head">
              <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
                {window.innerWidth < 768 && (
                  <button className="btn btn-sm btn-ghost" onClick={() => setMobileShowThread(false)}>←</button>
                )}
                <div>
                  <strong>{selected.contact_name || selected.contact_number}</strong>
                  <div style={{ fontSize: '0.78rem', color: 'var(--text-soft)' }}>
                    {selected.contact_number}
                    {totals?.messages_count > 0 && ` · ${totals.messages_count} msgs`}
                  </div>
                </div>
              </div>
              <label style={{ display: 'flex', alignItems: 'center', gap: '0.35rem', fontSize: '0.82rem' }}>
                <input type="checkbox" checked={selected.bot_enabled === 1}
                  onChange={e => toggleBot(e.target.checked)} />
                Bot IA
              </label>
            </div>
            <div className="thread-bg" ref={scrollRef}>
              {messages.map(m => (
                <div key={m.id} className={`msg-row ${m.direction === 'outbound' ? 'out' : 'in'}`}>
                  <div className="msg-bubble">
                    {m.body || (m.num_media > 0 ? '📎 Média' : '')}
                    {m.media_urls && (() => {
                      try {
                        const urls = JSON.parse(m.media_urls);
                        return urls.map((u, i) => <a key={i} href={u} target="_blank" rel="noreferrer" style={{ display: 'block', marginTop: '0.35rem', fontSize: '0.8rem' }}>Voir pièce jointe</a>);
                      } catch { return null; }
                    })()}
                    <div className="msg-meta">
                      {fmtTime(m.created_at)}
                      {m.direction === 'outbound' && <span className="msg-status">{statusIcon(m.status)}</span>}
                      {m.sent_by === 'bot' && ' · bot'}
                    </div>
                  </div>
                </div>
              ))}
            </div>
            <div className="compose">
              <textarea rows={1} placeholder="Répondre… (fenêtre 24h ou template requis)"
                value={draft} onChange={e => setDraft(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendReply(); } }} />
              <button className="btn btn-wa btn-sm" disabled={sending || !draft.trim()} onClick={sendReply}>
                {sending ? '…' : 'Envoyer'}
              </button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

// ==================== TEMPLATES ====================
function TemplatesView() {
  const { notify } = useApp();
  const [senders, setSenders] = useState([]);
  const [templates, setTemplates] = useState([]);
  const [senderId, setSenderId] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    api.get('/senders').then(r => {
      const list = r.senders || [];
      setSenders(list);
      if (list[0]?.id) setSenderId(list[0].id);
      setLoading(false);
    }).catch(() => setLoading(false));
  }, []);

  useEffect(() => {
    if (!senderId) return;
    api.get(`/senders/${senderId}/templates`).then(r => {
      setTemplates(r.templates || []);
    });
  }, [senderId]);

  return (
    <div style={{ flex: 1, overflow: 'auto' }}>
      <div className="panel-head" style={{ background: 'white', borderBottom: '1px solid var(--border)' }}>
        <strong>Templates WhatsApp</strong>
        {senders.length > 1 && (
          <select value={senderId || ''} onChange={e => setSenderId(Number(e.target.value))}
            style={{ font: 'inherit', padding: '0.35rem 0.5rem', borderRadius: 8, border: '1px solid var(--border)' }}>
            {senders.map(s => <option key={s.id} value={s.id}>{s.phone_number || s.label || s.id}</option>)}
          </select>
        )}
      </div>
      {loading && <div className="empty-state">Chargement…</div>}
      {!loading && templates.length === 0 && (
        <div className="empty-state">
          Aucun template approuvé. Les templates Meta permettent de contacter vos clients hors fenêtre 24h.
        </div>
      )}
      {templates.map(t => (
        <div key={t.id} className="template-row">
          <div>
            <strong>{t.name || t.friendly_name}</strong>
            <small>{t.category || 'utility'} · {t.approval_status || t.status || '-'}</small>
          </div>
          <span className="badge-unread" style={{ background: t.approval_status === 'approved' ? 'var(--wa)' : '#94a3b8' }}>
            {t.approval_status || 'pending'}
          </span>
        </div>
      ))}
    </div>
  );
}

// ==================== LIGNES WHATSAPP ====================
function LinesView({ userEmail }) {
  const { notify } = useApp();
  const [senders, setSenders] = useState([]);
  const [loading, setLoading] = useState(true);

  const load = useCallback(() => {
    setLoading(true);
    api.get('/senders').then(r => {
      if (r.error) { notify(r.error, 'error'); return; }
      const list = (r.senders || []).slice().sort((a, b) => {
        if (a.status === 'ONLINE' && b.status !== 'ONLINE') return -1;
        if (b.status === 'ONLINE' && a.status !== 'ONLINE') return 1;
        return (b.created_at || '').localeCompare(a.created_at || '');
      });
      setSenders(list);
    }).catch(() => notify('Erreur chargement', 'error'))
      .finally(() => setLoading(false));
  }, [notify]);

  useEffect(() => { load(); }, [load]);

  const active = senders.filter(s => s.status === 'ONLINE');

  const statusBadge = (status) => {
    const meta = SENDER_STATUS_META[status] || { label: status, cls: 'status-gray' };
    return <span className={`line-status ${meta.cls}`}>{meta.label}</span>;
  };

  return (
    <div className="lines-view">
      <div className="panel-head lines-head">
        <div>
          <strong>Lignes WhatsApp</strong>
          <p className="lines-sub">
            {active.length} active{active.length !== 1 ? 's' : ''} sur {senders.length} · compte Vocal {userEmail}
          </p>
        </div>
        <button className="btn btn-secondary btn-sm" onClick={load} disabled={loading}>
          <Icons.Refresh /> Actualiser
        </button>
      </div>

      {loading && <div className="empty-state">Chargement…</div>}

      {!loading && senders.length === 0 && (
        <div className="empty-state">
          Aucune ligne WhatsApp sur ce compte. Activez un numéro depuis my.vocal.ch (WhatsApp Business).
        </div>
      )}

      {!loading && senders.length > 0 && (
        <div className="lines-grid">
          {senders.map(s => {
            const phone = s.phone_number || s.line_phone || '-';
            const label = s.profile_name || s.display_name || s.line_label || s.friendly_name;
            return (
              <div key={s.id} className={`line-card ${s.status === 'ONLINE' ? 'line-active' : ''}`}>
                <div className="line-card-top">
                  <div className="line-phone">{phone}</div>
                  {statusBadge(s.status)}
                </div>
                {label && <div className="line-label">{label}</div>}
                <div className="line-meta">
                  {s.webhook_url ? (
                    <span className="line-tag line-tag-ok">Webhook configuré</span>
                  ) : (
                    <span className="line-tag">Webhook en attente</span>
                  )}
                  {s.source && <span className="line-tag">{s.source}</span>}
                </div>
                {s.status === 'ERRORED' && s.failure_reason && (
                  <div className="line-error">{s.failure_reason}</div>
                )}
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// ==================== STATS ====================
function StatsView() {
  const [data, setData] = useState({ conversations: 0, unread: 0, senders: 0 });
  useEffect(() => {
    Promise.all([api.get('/conversations'), api.get('/senders')]).then(([c, s]) => {
      const convs = c.conversations || [];
      setData({
        conversations: convs.length,
        unread: convs.reduce((a, x) => a + (x.unread_count || 0), 0),
        senders: (s.senders || []).length,
      });
    });
  }, []);
  return (
    <div className="stat-grid">
      <div className="stat-card"><div className="val">{data.conversations}</div><div className="lbl">Conversations actives</div></div>
      <div className="stat-card"><div className="val">{data.unread}</div><div className="lbl">Non lus</div></div>
      <div className="stat-card"><div className="val">{data.senders}</div><div className="lbl">Lignes WhatsApp</div></div>
    </div>
  );
}

// ==================== SHELL ====================
function AppShell({ user, onLogout }) {
  const { notify } = useApp();
  const [view, setView] = useState('inbox');

  const openMobileApp = async () => {
    try {
      const r = await api.post('/magic-link', { target: CONFIG.APP_URL });
      if (r.url) window.open(r.url, '_blank');
      else notify(r.error || 'Erreur', 'error');
    } catch { notify('Erreur', 'error'); }
  };

  return (
    <div className="shell">
      <nav className="shell-nav">
        <div className="nav-brand">
          <div className="nav-brand-icon"><Icons.Chat /></div>
          <strong>Botman</strong>
        </div>
        <button className={`nav-item ${view === 'inbox' ? 'active' : ''}`} onClick={() => setView('inbox')}>
          <Icons.Chat /> Conversations
        </button>
        <button className={`nav-item ${view === 'templates' ? 'active' : ''}`} onClick={() => setView('templates')}>
          <Icons.Template /> Templates
        </button>
        <button className={`nav-item ${view === 'lines' ? 'active' : ''}`} onClick={() => setView('lines')}>
          <Icons.Line /> Lignes WhatsApp
        </button>
        <button className={`nav-item ${view === 'stats' ? 'active' : ''}`} onClick={() => setView('stats')}>
          <Icons.Stats /> Statistiques
        </button>
        <div className="nav-spacer" />
        <button className="nav-item" onClick={openMobileApp}>
          <Icons.Phone /> App mobile <Icons.External />
        </button>
        <div className="nav-user">
          {user.email}
          <button className="nav-item" style={{ marginTop: '0.5rem', padding: '0.5rem' }} onClick={onLogout}>
            Déconnexion
          </button>
        </div>
      </nav>
      <main className="shell-main">
        {view === 'inbox' && <InboxView />}
        {view === 'templates' && <TemplatesView />}
        {view === 'lines' && <LinesView userEmail={user.email} />}
        {view === 'stats' && <StatsView />}
      </main>
    </div>
  );
}

// ==================== ROOT ====================
function AppProvider({ children }) {
  const [toast, setToast] = useState(null);
  const notify = useCallback((msg, type) => setToast({ msg, type }), []);
  return (
    <AppCtx.Provider value={{ notify }}>
      {children}
      {toast && <Toast msg={toast.msg} type={toast.type} onDone={() => setToast(null)} />}
    </AppCtx.Provider>
  );
}

function App() {
  const [user, setUser] = useState(null);
  const [booting, setBooting] = useState(true);

  useEffect(() => {
    const token = localStorage.getItem(STORAGE_TOKEN);
    const saved = localStorage.getItem(STORAGE_USER);
    if (token) {
      api.token = token;
      if (saved) {
        try { setUser(JSON.parse(saved)); } catch {}
      }
      api.get('/me').then(r => {
        if (r.error) {
          localStorage.removeItem(STORAGE_TOKEN);
          localStorage.removeItem(STORAGE_USER);
          api.token = null;
        } else if (r.user || r.email) {
          setUser(r.user || r);
        }
      }).finally(() => setBooting(false));
    } else setBooting(false);
  }, []);

  const onLogin = (token, u) => {
    api.token = token;
    localStorage.setItem(STORAGE_TOKEN, token);
    localStorage.setItem(STORAGE_USER, JSON.stringify(u));
    setUser(u);
  };

  const onLogout = () => {
    localStorage.removeItem(STORAGE_TOKEN);
    localStorage.removeItem(STORAGE_USER);
    api.token = null;
    setUser(null);
  };

  if (booting) return <div className="app-loading"><div className="loading-spinner" /></div>;
  if (!user) return <AuthScreen onLogin={onLogin} />;
  return <AppShell user={user} onLogout={onLogout} />;
}

const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<AppProvider><App /></AppProvider>);

document.getElementById('app-loading')?.remove();
