const { useState, useEffect, useMemo, useRef } = React;

// Utility: format euro
const eur = (n) => `€${n.toLocaleString('it-IT', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}`;

const priceRange = (p) => `${eur(p.priceMin)}–${eur(p.priceMax)}`;

const TIERS = {
  base: { label: 'Base', cls: '' },
  mid: { label: 'Mid', cls: 'mid' },
  premium: { label: 'Rara', cls: 'premium' },
};

// ============ Top Bar ============
const NAV_ITEMS = ['Catalogo', 'Aste', 'Bundle', 'Ambiente', 'Propagazione', 'Diario', 'Chi siamo'];
const MOBILE_EXTRA = ['Prenotazioni', 'Wishlist', 'Ordini', 'FAQ', 'Contatti'];

const TopBar = ({ cartCount, onCartClick, onLogoClick, activeSection, onNav, onSearch, onAccount }) => {
  const [menuOpen, setMenuOpen] = useState(false);
  // Blocca lo scroll del sito quando il menu mobile è aperto
  useEffect(() => {
    document.body.style.overflow = menuOpen ? 'hidden' : '';
    return () => { document.body.style.overflow = ''; };
  }, [menuOpen]);
  const go = (n) => { onNav(n); setMenuOpen(false); };
  return (
    <div className="topbar">
      <div className="topbar-grid">
        <button
          className="burger-btn"
          aria-label="Apri il menu"
          aria-expanded={menuOpen}
          onClick={() => setMenuOpen(true)}
        >
          <span /><span /><span />
        </button>
        <div className="logo" onClick={onLogoClick} style={{ cursor: 'pointer' }}>
          <div className="logo-mark"><Logo /></div>
          <span>Florilegio</span>
        </div>
        <nav className="nav">
          {NAV_ITEMS.map((n) => (
            <a key={n} onClick={() => onNav(n)} className={activeSection === n ? 'active' : ''} style={{ cursor: 'pointer' }}>{n}</a>
          ))}
        </nav>
        <div className="top-right">
          <button className="icon-btn" title="Cerca" onClick={onSearch}><Icon name="search" size={17} /></button>
          <button className="icon-btn hide-mobile" title="Profilo" onClick={onAccount}><Icon name="user" size={17} /></button>
          <button className="icon-btn" title="Carrello" onClick={onCartClick}>
            <Icon name="cart" size={17} />
            {cartCount > 0 && <span className="cart-badge">{cartCount}</span>}
          </button>
        </div>
      </div>

      {/* Menu mobile a tutta pagina */}
      <div className={`mobile-menu-overlay ${menuOpen ? 'open' : ''}`} onClick={() => setMenuOpen(false)} />
      <aside className={`mobile-menu ${menuOpen ? 'open' : ''}`} aria-hidden={!menuOpen}>
        <div className="mobile-menu-head">
          <div className="logo"><div className="logo-mark"><Logo /></div><span>Florilegio</span></div>
          <button className="icon-btn" aria-label="Chiudi il menu" onClick={() => setMenuOpen(false)}>
            <Icon name="close" size={18} />
          </button>
        </div>
        <nav className="mobile-nav">
          {NAV_ITEMS.map((n) => (
            <button key={n} className={activeSection === n ? 'active' : ''} onClick={() => go(n)}>
              {n}<Icon name="arrow_right" size={14} />
            </button>
          ))}
          <div className="mobile-nav-sep" />
          {MOBILE_EXTRA.map((n) => (
            <button key={n} className={`sub ${activeSection === n ? 'active' : ''}`} onClick={() => go(n)}>
              {n}<Icon name="arrow_right" size={13} />
            </button>
          ))}
          <div className="mobile-nav-sep" />
          <button className="sub" onClick={() => { onAccount(); setMenuOpen(false); }}>
            Il mio profilo<Icon name="arrow_right" size={13} />
          </button>
        </nav>
        <div className="mobile-menu-foot">
          <a href="mailto:info@florilegio.online">info@florilegio.online</a>
          <span>Milano · Spedizioni in tutta Italia</span>
        </div>
      </aside>
    </div>
  );
};

// ============ Search Overlay ============
const SearchOverlay = ({ open, onClose, onOpenPlant, onNav }) => {
  const [q, setQ] = useState('');
  const inputRef = useRef(null);
  useEffect(() => { if (open) { setQ(''); setTimeout(() => inputRef.current?.focus(), 80); } }, [open]);
  useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    if (open) window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);
  if (!open) return null;
  const ql = q.trim().toLowerCase();
  // Cerca anche fra le condizioni di coltivazione: "poca luce", "senza teca"
  // e "principiante" prima non restituivano nulla, pur essendo informazioni
  // presenti su ogni scheda.
  const results = ql.length >= 1 ? cercaPiante(CATALOG.plants, ql, CATALOG.categories).slice(0, 12) : [];
  // Ogni suggerimento è verificato: prima "In casa" e "In arrivo" portavano a
  // zero risultati, perché la ricerca non guardava nella categoria.
  const suggestions = ['Begonia', 'Alocasia', 'Poca luce', 'Casa normale', 'Variegata', 'Sole diretto'];
  return (
    <div className="search-overlay" onClick={onClose}>
      <div className="search-panel" onClick={(e) => e.stopPropagation()}>
        <div className="search-bar">
          <Icon name="search" size={18} />
          <input ref={inputRef} placeholder="Cerca specie, famiglia o condizioni: «poca luce»…" value={q} onChange={(e) => setQ(e.target.value)} />
          <button className="search-close" onClick={onClose} aria-label="Chiudi"><Icon name="x" size={16} /></button>
        </div>
        {!ql && (
          <div className="search-suggest">
            <div className="mono search-suggest-label">Suggerimenti</div>
            <div className="search-chips">
              {suggestions.map(s => (
                <button key={s} className="search-chip" onClick={() => setQ(s)}>{s}</button>
              ))}
            </div>
          </div>
        )}
        {ql && (
          <div className="search-results">
            <div className="mono search-suggest-label">{results.length} risultat{results.length === 1 ? 'o' : 'i'}</div>
            {results.length === 0 && (
              <div className="search-empty">Nessun risultato per <em>"{q}"</em></div>
            )}
            {results.map(p => {
              const cat = CATALOG.categories.find(c => c.id === p.cat);
              return (
                <button key={p.id} className="search-result" onClick={() => { onOpenPlant(p); onClose(); }}>
                  <div className="search-result-name serif">{p.name}</div>
                  <div className="search-result-meta mono">
                    <span>{p.family}</span>
                    <span className="dot" />
                    <span>{cat?.title}</span>
                    <span className="dot" />
                    <span>{priceRange(p)}</span>
                  </div>
                </button>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
};

const ORDER_STATUS_LABEL = {
  nuovo: 'In lavorazione', preparazione: 'In preparazione',
  spedito: 'Spedito', consegnato: 'Consegnato', annullato: 'Annullato',
};

// ============ Account Drawer ============
const AccountDrawer = ({ open, onClose, saved, cart, onOpenPlant, onNav, auth }) => {
  const { user, token, login, logout, googleClientId } = auth;
  const [view, setView] = useState('signin'); // signin | signup
  const [form, setForm] = useState({ name: '', email: '', password: '' });
  const [err, setErr] = useState('');
  const [busy, setBusy] = useState(false);
  const [orders, setOrders] = useState([]);
  const googleBtnRef = useRef(null);

  useEffect(() => { if (open && !user) { setView('signin'); setErr(''); } }, [open, user]);

  // Storico ordini reale del cliente, dal server
  useEffect(() => {
    if (!open || !token) { setOrders([]); return; }
    fetch('/api/auth/orders', { headers: { Authorization: `Bearer ${token}` } })
      .then(r => r.ok ? r.json() : [])
      .then(setOrders)
      .catch(() => setOrders([]));
  }, [open, token]);

  // Pulsante Google ufficiale, disegnato da Google stesso
  useEffect(() => {
    if (!open || user || !googleClientId || !googleBtnRef.current) return;
    let cancelled = false;
    const render = () => {
      if (cancelled || !window.google?.accounts?.id || !googleBtnRef.current) return;
      window.google.accounts.id.initialize({
        client_id: googleClientId,
        callback: async (resp) => {
          setBusy(true); setErr('');
          try {
            const r = await fetch('/api/auth/google', {
              method: 'POST', headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ credential: resp.credential }),
            });
            const data = await r.json();
            if (!r.ok) throw new Error(data.error || 'Accesso con Google non riuscito');
            login(data.token, data.user);
          } catch (e) { setErr(e.message); } finally { setBusy(false); }
        },
      });
      googleBtnRef.current.innerHTML = '';
      window.google.accounts.id.renderButton(googleBtnRef.current, {
        theme: 'outline', size: 'large', width: 320, text: 'continue_with', locale: 'it',
      });
    };
    if (window.google?.accounts?.id) render();
    else {
      const s = document.createElement('script');
      s.src = 'https://accounts.google.com/gsi/client';
      s.async = true; s.defer = true; s.onload = render;
      document.head.appendChild(s);
    }
    return () => { cancelled = true; };
  }, [open, user, googleClientId, login]);

  const submit = async (e) => {
    e.preventDefault();
    setErr(''); setBusy(true);
    try {
      const path = view === 'signup' ? '/api/auth/register' : '/api/auth/login';
      const body = view === 'signup'
        ? { name: form.name, email: form.email, password: form.password }
        : { email: form.email, password: form.password };
      const r = await fetch(path, {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
      const data = await r.json();
      if (!r.ok) throw new Error(data.error || 'Operazione non riuscita');
      login(data.token, data.user);
      setForm({ name: '', email: '', password: '' });
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  const savedPlants = saved.map(id => CATALOG.plants.find(p => p.id === id)).filter(Boolean);

  return (
    <>
      <div className={`drawer-overlay ${open ? 'open' : ''}`} onClick={onClose}></div>
      <aside className={`drawer account-drawer ${open ? 'open' : ''}`}>
        <div className="drawer-head">
          <div>
            <div className="mono" style={{ color: 'var(--ink-mute)', marginBottom: 4 }}>Profilo</div>
            <h3 className="serif" style={{ fontSize: '1.6rem' }}>{user ? `Ciao, ${user.name}` : 'Accedi'}</h3>
          </div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={16} /></button>
        </div>

        {user && (
          <div className="account-body">
            <div className="account-card">
              <div className="mono" style={{ color: 'var(--ink-mute)', marginBottom: 6 }}>
                Account {user.provider === 'google' ? '· via Google' : ''}
              </div>
              <div className="serif" style={{ fontSize: '1.2rem' }}>{user.email}</div>
              {user.since && <div className="mono" style={{ color: 'var(--ink-mute)', fontSize: '.62rem', marginTop: 6 }}>
                Cliente dal {new Date(user.since).toLocaleDateString('it-IT', { month: 'long', year: 'numeric' })}
              </div>}
            </div>

            <div className="account-section">
              <div className="account-section-head">
                <h4 className="serif">Wishlist</h4>
                <span className="mono">{savedPlants.length}</span>
              </div>
              {savedPlants.length === 0 && <div className="account-empty">Nessuna pianta salvata. Tocca il cuore su una scheda per salvarla.</div>}
              {savedPlants.map(p => (
                <button key={p.id} className="account-row" onClick={() => { onOpenPlant(p); onClose(); }}>
                  <div className="serif">{p.name}</div>
                  <div className="mono" style={{ color: 'var(--ink-mute)' }}>{priceRange(p)}</div>
                </button>
              ))}
            </div>

            <div className="account-section">
              <div className="account-section-head">
                <h4 className="serif">Ordini</h4>
                <span className="mono">{orders.length}</span>
              </div>
              {orders.length === 0 && <div className="account-empty">Nessun ordine ancora. Quando completi un acquisto lo trovi qui.</div>}
              {orders.map(o => (
                <div key={o.id} className="account-row" style={{ cursor: 'default' }}>
                  <div>
                    <div className="serif">Ordine {o.id}</div>
                    <div className="mono" style={{ color: 'var(--ink-mute)', fontSize: '.65rem' }}>
                      {new Date(o.date).toLocaleDateString('it-IT')} · {o.items.length} articol{o.items.length === 1 ? 'o' : 'i'}
                      {' · '}{ORDER_STATUS_LABEL[o.adminStatus] || 'In lavorazione'}
                      {o.tracking ? ` · ${o.tracking}` : ''}
                    </div>
                  </div>
                  <div className="serif">{eur(o.total)}</div>
                </div>
              ))}
            </div>

            <div className="account-section">
              <div className="account-section-head">
                <h4 className="serif">Carrello</h4>
                <span className="mono">{cart.reduce((s, i) => s + i.qty, 0)} pezzi</span>
              </div>
              <div className="account-empty" style={{ padding: '6px 0' }}>{cart.length === 0 ? 'Vuoto' : `${cart.length} articol${cart.length === 1 ? 'o' : 'i'} in attesa.`}</div>
            </div>

            <button className="btn-ghost" style={{ width: '100%', marginTop: 24 }} onClick={logout}>
              Esci
            </button>
          </div>
        )}

        {!user && (
          <form onSubmit={submit} className="account-body">
            <div className="auth-tabs">
              <button type="button" className={view === 'signin' ? 'active' : ''} onClick={() => { setView('signin'); setErr(''); }}>Accedi</button>
              <button type="button" className={view === 'signup' ? 'active' : ''} onClick={() => { setView('signup'); setErr(''); }}>Registrati</button>
            </div>

            {googleClientId && (
              <>
                <div ref={googleBtnRef} className="google-btn-wrap" />
                <div className="auth-divider"><span>oppure con email</span></div>
              </>
            )}

            {view === 'signup' && (
              <div className="field">
                <label>Nome</label>
                <input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })}
                  autoComplete="name" required />
              </div>
            )}
            <div className="field">
              <label>Email</label>
              <input type="email" value={form.email} onChange={(e) => setForm({ ...form, email: e.target.value })}
                autoComplete="email" required />
            </div>
            <div className="field">
              <label>Password</label>
              <input type="password" value={form.password} onChange={(e) => setForm({ ...form, password: e.target.value })}
                autoComplete={view === 'signup' ? 'new-password' : 'current-password'}
                minLength={view === 'signup' ? 8 : undefined} required />
              {view === 'signup' && <div className="field-hint">Almeno 8 caratteri.</div>}
            </div>

            {err && <div className="auth-error" role="alert">{err}</div>}

            <button type="submit" className="btn-primary" style={{ width: '100%', marginTop: 8 }} disabled={busy}>
              {busy ? 'Attendi…' : (view === 'signin' ? 'Accedi al vivaio' : 'Crea account')}
            </button>
            <div className="auth-foot mono">
              {view === 'signin' ? 'Non hai un account?' : 'Hai già un account?'}
              <button type="button" onClick={() => { setView(view === 'signin' ? 'signup' : 'signin'); setErr(''); }}>
                {view === 'signin' ? 'Registrati' : 'Accedi'}
              </button>
            </div>
            <p className="auth-privacy">
              Creando un account accetti i <a onClick={() => { onNav?.('Termini'); onClose(); }}>termini</a> e
              la <a onClick={() => { onNav?.('Privacy'); onClose(); }}>privacy policy</a>.
            </p>
          </form>
        )}
      </aside>
    </>
  );
};

// ============ Hero ============
const Hero = () => {
  const sellable = CATALOG.plants.filter(p => p.status !== 'material');
  const total = sellable.length;
  const cats = CATALOG.categories.filter(c => c.id !== 'materiali').length;
  const prices = sellable.map(p => p.priceMin).filter(Boolean);
  const pricesMax = sellable.map(p => p.priceMax).filter(Boolean);
  const minP = Math.min(...prices);
  const maxP = Math.max(...pricesMax);
  return (
    <section className="hero">
      <div className="hero-meta mono">
        <span>Edizione N.01 — Primavera 2026</span>
        <span className="line" />
        <span>Milano · IT</span>
      </div>
      <h1 className="hero-title">
        Un <em>florilegio</em> di<br />
        piante esotiche,<br />
        coltivate con metodo.
      </h1>
      <div className="hero-sub">
        <p>
          Piccolo vivaio domestico dedicato a <em>begonie rare</em>, <em>aracee da sottobosco</em> e <em>melastomatacee tropicali</em>. Ogni pianta è propagata in casa con substrati su misura, schede tecniche complete e tempi di radicazione verificati. Spedizione in tutta Italia.
        </p>
        <div className="hero-stats">
          <div className="stat"><div className="stat-num">{total}</div><div className="stat-lbl">Varietà</div></div>
          <div className="stat"><div className="stat-num">{cats}</div><div className="stat-lbl">Categorie</div></div>
          <div className="stat"><div className="stat-num">€{minP}–{maxP}</div><div className="stat-lbl">Range</div></div>
        </div>
      </div>
    </section>
  );
};

// ============ Toolbar ============
const Toolbar = ({ activeCat, setActiveCat, query, setQuery, view, setView, tierFilter, setTierFilter,
                   luceFilter, setLuceFilter, umiditaFilter, setUmiditaFilter,
                   soloDisponibili, setSoloDisponibili, onGuida, risultati, onAzzera }) => {
  const counts = useMemo(() => {
    const m = {};
    CATALOG.plants.forEach((p) => { m[p.cat] = (m[p.cat] || 0) + 1; });
    m.all = CATALOG.plants.length;
    return m;
  }, []);
  // Le categorie senza piante non vengono mostrate: annunciarle con titolo e
  // descrizione per poi non offrire nulla è peggio che ometterle.
  const all = [{ id: 'all', num: '*', title: 'Tutte' }, ...CATALOG.categories.filter(c => counts[c.id] > 0)];
  const filtriAttivi = activeCat !== 'all' || tierFilter !== 'all' || luceFilter !== 'all'
    || umiditaFilter !== 'all' || soloDisponibili || !!query;

  return (
    <div className="toolbar">
      <div className="chip-row">
        {all.map((c) => (
          <button key={c.id} className={`chip ${activeCat === c.id ? 'active' : ''}`} onClick={() => setActiveCat(c.id)}>
            {c.id !== 'all' && <span style={{ fontFamily: 'var(--mono)', fontSize: '.6rem', opacity: .6 }}>{c.num}</span>}
            <span>{c.title}</span>
            <span className="count">{counts[c.id] || 0}</span>
          </button>
        ))}
      </div>

      <div className="filtri-cura">
        <button className="btn-guida" onClick={onGuida}>
          <Icon name="search" size={13} /> Trova la pianta adatta a te
        </button>
        <div className="filtro-gruppo">
          <span className="mono filtro-eti">Luce</span>
          {[['all', 'Qualsiasi'], ['bassa', 'Poca'], ['media', 'Media'], ['brillante', 'Molta'], ['sole', 'Sole diretto']].map(([k, l]) => (
            <button key={k} className={`chip chip-sm ${luceFilter === k ? 'active' : ''}`} onClick={() => setLuceFilter(k)}>{l}</button>
          ))}
        </div>
        <div className="filtro-gruppo">
          <span className="mono filtro-eti">Umidità</span>
          {[['all', 'Qualsiasi'], ['normale', 'Casa normale'], ['alta', 'Alta'], ['teca', 'Teca o serra']].map(([k, l]) => (
            <button key={k} className={`chip chip-sm ${umiditaFilter === k ? 'active' : ''}`} onClick={() => setUmiditaFilter(k)}>{l}</button>
          ))}
        </div>
        <div className="filtro-gruppo">
          <button className={`chip chip-sm ${soloDisponibili ? 'active' : ''}`} onClick={() => setSoloDisponibili(v => !v)}>
            Solo disponibili
          </button>
          {filtriAttivi && (
            <button className="chip chip-sm chip-azzera" onClick={onAzzera}>Azzera filtri</button>
          )}
          <span className="mono filtro-conteggio">
            {risultati} {risultati === 1 ? 'pianta' : 'piante'}
          </span>
        </div>
      </div>
      <div className="toolbar-right">
        <div className="chip-row tier-row">
          {[['all', 'Tutte'], ['base', 'Base'], ['mid', 'Mid'], ['premium', 'Rare']].map(([k, l]) => (
            <button key={k} className={`chip ${tierFilter === k ? 'active' : ''}`} onClick={() => setTierFilter(k)}>{l}</button>
          ))}
        </div>
        <div className="search-box">
          <Icon name="search" size={14} />
          <input placeholder="Cerca specie, famiglia…" value={query} onChange={(e) => setQuery(e.target.value)} />
        </div>
        <div className="view-toggle">
          <button className={view === 'grid' ? 'active' : ''} onClick={() => setView('grid')} title="Griglia"><Icon name="grid" size={14} /></button>
          <button className={view === 'list' ? 'active' : ''} onClick={() => setView('list')} title="Lista"><Icon name="list" size={14} /></button>
        </div>
      </div>
    </div>
  );
};

// ============ Avvisami quando torna disponibile ============
// Sostituisce il pulsante "Esaurito", che era un vicolo cieco: il visitatore
// interessato se ne andava senza lasciare traccia. Qui la domanda viene
// raccolta, e l'avviso parte da solo quando la giacenza torna sopra zero.
const AvvisamiQuandoTorna = ({ plant }) => {
  const [aperto, setAperto] = useState(false);
  const [email, setEmail] = useState('');
  const [stato, setStato] = useState(null); // null | 'invio' | 'fatto' | messaggio d'errore

  // Cambiando pianta il modulo riparte pulito, altrimenti resterebbe
  // la conferma della richiesta precedente.
  useEffect(() => { setAperto(false); setEmail(''); setStato(null); }, [plant.id]);

  const invia = async (e) => {
    e.preventDefault();
    setStato('invio');
    try {
      const r = await fetch('/api/attese', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, plantId: plant.id }),
      });
      const j = await r.json().catch(() => ({}));
      setStato(r.ok ? 'fatto' : (j.error || 'Non è stato possibile registrare la richiesta'));
    } catch {
      setStato('Connessione non riuscita. Riprova fra poco.');
    }
  };

  if (stato === 'fatto') {
    return (
      <div className="avvisami-ok" style={{ flex: 1 }}>
        <Icon name="check" size={15} />
        <span>Ti scriverò appena torna disponibile.</span>
      </div>
    );
  }

  if (!aperto) {
    return (
      <button className="btn-primary" style={{ flex: 1 }} onClick={() => setAperto(true)}>
        <Icon name="alert" size={15} />
        {plant.status === 'coming_soon' ? 'Avvisami quando arriva' : 'Avvisami quando torna'}
      </button>
    );
  }

  return (
    <form className="avvisami-form" style={{ flex: 1 }} onSubmit={invia}>
      <input type="email" required value={email} autoFocus
        placeholder="La tua email" aria-label="La tua email"
        onChange={(e) => { setEmail(e.target.value); if (stato && stato !== 'invio') setStato(null); }} />
      <button className="btn-primary" type="submit" disabled={stato === 'invio'}>
        {stato === 'invio' ? 'Invio…' : 'Avvisami'}
      </button>
      {stato && stato !== 'invio' && <div className="avvisami-err">{stato}</div>}
    </form>
  );
};

// ============ Guida "adatta a te" ============
// Due domande, non un questionario: sono le uniche due variabili che
// determinano davvero se una di queste piante sopravvive in casa di qualcuno.
// Le risposte impostano i filtri del catalogo, così restano modificabili dopo.
const GuidaAdatta = ({ open, onClose, onApplica }) => {
  const [luce, setLuce] = useState(null);
  const [umidita, setUmidita] = useState(null);
  useEffect(() => { if (open) { setLuce(null); setUmidita(null); } }, [open]);
  useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    if (open) window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);
  if (!open) return null;

  const risultati = CATALOG.plants.filter(p =>
    (!luce || luciDi(p).includes(luce)) && (!umidita || umiditaDi(p) === umidita)
  ).length;

  const DOM_LUCE = [
    ['bassa', 'Finestra a nord, o stanza poco luminosa'],
    ['media', 'Luce buona, ma senza sole diretto'],
    ['brillante', 'Molto luminosa per gran parte del giorno'],
    ['sole', 'Il sole batte direttamente sulle piante'],
  ];
  const DOM_UMIDITA = [
    ['normale', 'Casa normale, senza nulla di particolare'],
    ['alta', 'Posso usare un umidificatore o un bagno luminoso'],
    ['teca', 'Ho una teca o una piccola serra'],
  ];

  return (
    <div className="search-overlay" onClick={onClose}>
      <div className="guida-panel" onClick={(e) => e.stopPropagation()}>
        <div className="guida-head">
          <div>
            <div className="mono guida-eyebrow">Due domande</div>
            <h2 className="serif guida-titolo">Dove vivranno le piante?</h2>
          </div>
          <button className="search-close" onClick={onClose} aria-label="Chiudi"><Icon name="x" size={16} /></button>
        </div>

        <div className="guida-dom">
          <div className="mono guida-eti">1 · Quanta luce c’è nel punto in cui le terrai?</div>
          {DOM_LUCE.map(([k, testo]) => (
            <button key={k} className={`guida-opt ${luce === k ? 'active' : ''}`} onClick={() => setLuce(k)}>
              <span className="guida-radio" />{testo}
            </button>
          ))}
        </div>

        <div className="guida-dom">
          <div className="mono guida-eti">2 · Quanta umidità puoi garantire?</div>
          {DOM_UMIDITA.map(([k, testo]) => (
            <button key={k} className={`guida-opt ${umidita === k ? 'active' : ''}`} onClick={() => setUmidita(k)}>
              <span className="guida-radio" />{testo}
            </button>
          ))}
          <p className="guida-nota">
            È la variabile che fa fallire più acquisti. Molte di queste specie vengono dal sottobosco
            tropicale e in un appartamento asciutto soffrono, per quanta cura ci si metta.
          </p>
        </div>

        <div className="guida-foot">
          <div className="guida-conteggio">
            {(luce || umidita)
              ? <><strong>{risultati}</strong> {risultati === 1 ? 'pianta adatta' : 'piante adatte'}</>
              : 'Scegli almeno una risposta'}
          </div>
          <button className="btn-primary" disabled={!luce && !umidita}
            onClick={() => { onApplica(luce, umidita); onClose(); }}>
            Mostra le piante <Icon name="arrow" size={14} />
          </button>
        </div>
      </div>
    </div>
  );
};

// ============ Product Card ============
// Acquistabile solo se in vendita E con giacenza reale.
// I preordini sono disattivati: non si prenota nulla, si vende solo il disponibile.
const isBuyable = (p) => p.status === 'available' && p.stock > 0;
const stockLabel = (p) => {
  if (p.status === 'coming_soon') return { text: 'In arrivo', cls: 'soon' };
  if (!isBuyable(p)) return { text: 'Esaurito', cls: 'out' };
  return p.stock <= 5 ? { text: `Solo ${p.stock}`, cls: 'low' } : { text: `${p.stock} disp.`, cls: '' };
};

// Riga compatta con le due condizioni che determinano se una pianta
// sopravvive a casa di chi la compra. La temperatura è quasi sempre quella
// domestica, quindi non entra: occuperebbe spazio senza aiutare a scegliere.
const CuraSintesi = ({ plant }) => {
  const luci = luciDi(plant);
  const um = umiditaDi(plant);
  return (
    <div className="cura-sintesi" title={`Luce: ${plant.light}\nUmidità: ${plant.humidity}\nTemperatura: ${plant.temp}`}>
      <span className="cura-voce">
        <Icon name="sun" size={11} />
        {ETICHETTE_LUCE[luci[0]]}
      </span>
      <span className={`cura-voce cura-${um}`}>
        <Icon name="droplet" size={11} />
        {ETICHETTE_UMIDITA[um]}
      </span>
    </div>
  );
};

const ProductCard = ({ plant, index, onOpen, onQuickAdd, saved, onSave }) => {
  const tier = TIERS[plant.tier];
  const st = stockLabel(plant);
  const buyable = isBuyable(plant);
  const no = String(index + 1).padStart(3, '0');
  return (
    <article className={`card ${buyable ? '' : 'unavailable'}`} onClick={() => onOpen(plant)}>
      <div className="card-img">
        <PlantArt plant={plant} />
        <div className="card-no">N.{no}</div>
        <div className={`card-tier ${tier.cls}`}>{tier.label}</div>
        <div className={`card-stock ${st.cls}`}>
          <span className={`stock-dot ${st.cls}`} />
          {st.text}
        </div>
      </div>
      <div className="card-body">
        <div className="card-family">{plant.family}</div>
        <h3 className="card-name">{plant.name}</h3>
        <div className="card-origin">{plant.origin}</div>
        {/* Cura a colpo d'occhio: su piante esotiche è l'informazione che
            decide l'acquisto, e finora era sepolta nella scheda di dettaglio. */}
        <CuraSintesi plant={plant} />
        <div className="card-foot">
          <div className="card-price">
            <span className="from">Da</span>
            {eur(plant.priceMin)}
          </div>
          {buyable ? (
            <button className="card-add" onClick={(e) => { e.stopPropagation(); onQuickAdd(plant); }} title="Aggiungi al carrello" aria-label={`Aggiungi ${plant.name} al carrello`}>
              <Icon name="plus" size={16} />
            </button>
          ) : (
            <button className="card-add disabled" disabled title="Non disponibile" aria-label={`${plant.name} non disponibile`}>
              <Icon name="close" size={14} />
            </button>
          )}
        </div>
      </div>
    </article>
  );
};

// ============ List Row ============
const ListRow = ({ plant, index, onOpen, onQuickAdd }) => {
  const tier = TIERS[plant.tier];
  const no = String(index + 1).padStart(3, '0');
  return (
    <div className="list-row" onClick={() => onOpen(plant)}>
      <div className="mono lr-no">N.{no}</div>
      <div className="thumb"><PlantArt plant={plant} /></div>
      <div>
        <div className="lr-name">{plant.name}</div>
        <div className="lr-family">{plant.family} · {plant.origin}</div>
      </div>
      <div className="lr-origin">{plant.prop}</div>
      <div><span className={`card-tier ${tier.cls}`} style={{ position: 'static', display: 'inline-block' }}>{tier.label}</span></div>
      <div className="lr-price">{priceRange(plant)}</div>
      {isBuyable(plant) ? (
        <button className="card-add" onClick={(e) => { e.stopPropagation(); onQuickAdd(plant); }} aria-label={`Aggiungi ${plant.name} al carrello`}>
          <Icon name="plus" size={16} />
        </button>
      ) : (
        <button className="card-add disabled" disabled title="Non disponibile"><Icon name="close" size={14} /></button>
      )}
    </div>
  );
};

// ============ Category Section ============
const CategorySection = ({ cat, plants, view, onOpen, onQuickAdd }) => {
  if (plants.length === 0) return null;
  return (
    <section className="cat-section" id={`cat-${cat.id}`}>
      <div className="cat-header">
        <div className="cat-num">
          {cat.num.split('').map((c, i) => <span key={i}>{c}</span>)}
        </div>
        <div className="cat-meta">
          <div className="mono">Categoria {cat.num} · {plants.length} varietà</div>
          <h2 className="cat-title">{cat.title}</h2>
          <div className="cat-subtitle">{cat.subtitle}</div>
          <p className="cat-blurb">{cat.blurb}</p>
          <div className="cat-diff">
            <span className="mono" style={{ color: 'var(--ink-mute)' }}>Difficoltà propagazione</span>
            <div className="diff-pips">
              {[1,2,3].map((i) => <span key={i} className={`diff-pip ${i <= cat.difficulty ? 'on' : ''}`} />)}
            </div>
          </div>
        </div>
      </div>
      {view === 'grid' ? (
        <div className="grid">
          {plants.map((p, i) => (
            <ProductCard key={p.id} plant={p} index={i} onOpen={onOpen} onQuickAdd={onQuickAdd} />
          ))}
        </div>
      ) : (
        <div className="list">
          <div className="list-head">
            <div>N.</div><div></div><div>Specie</div><div className="lrh-origin">Propagazione</div><div className="lrh-family">Tier</div><div>Prezzo</div><div></div>
          </div>
          {plants.map((p, i) => (
            <ListRow key={p.id} plant={p} index={i} onOpen={onOpen} onQuickAdd={onQuickAdd} />
          ))}
        </div>
      )}
    </section>
  );
};

// ============ Detail Drawer ============
const Detail = ({ plant, open, onClose, onAdd, saved, onSave }) => {
  const [qty, setQty] = useState(1);
  const [tab, setTab] = useState('cura');
  const [added, setAdded] = useState(false);
  const [shared, setShared] = useState(false);
  useEffect(() => { if (open) { setQty(1); setTab('cura'); setAdded(false); } }, [open, plant?.id]);

  if (!plant) return null;
  const tier = TIERS[plant.tier];
  const midPrice = Math.round((plant.priceMin + plant.priceMax) / 2);

  const handleAdd = () => {
    onAdd(plant, qty);
    setAdded(true);
    setTimeout(() => setAdded(false), 1600);
  };

  const buyable = isBuyable(plant);

  // Condivisione: usa il pannello nativo del telefono se disponibile,
  // altrimenti copia il link negli appunti.
  const sharePlant = async () => {
    const url = `${location.origin}${location.pathname}#pianta-${plant.id}`;
    const data = { title: `${plant.name} — Florilegio`, text: `${plant.name} (${plant.family}) su Florilegio`, url };
    try {
      if (navigator.share) { await navigator.share(data); return; }
      await navigator.clipboard.writeText(url);
      setShared(true);
      setTimeout(() => setShared(false), 1800);
    } catch { /* l'utente ha annullato la condivisione */ }
  };

  return (
    <>
      <div className={`drawer-overlay ${open ? 'open' : ''}`} onClick={onClose} />
      <aside className={`drawer ${open ? 'open' : ''}`}>
        <div className="drawer-head">
          <button className="close-btn" onClick={onClose}>
            <Icon name="arrow_left" size={14} /> Torna al catalogo
          </button>
          <div className="mono" style={{ color: 'var(--ink-mute)' }}>
            Scheda tecnica · {plant.family}
          </div>
        </div>

        <div className="d-hero">
          <div className="d-img">
            <PhotoGallery key={plant.id} plant={plant} />
          </div>
          <div className="d-info">
            <div className="d-tag">
              <span className="mono">{plant.family}</span>
              <span className="dot" />
              <span className="mono">{CATALOG.categories.find(c => c.id === plant.cat).title}</span>
              <span className={`card-tier ${tier.cls}`} style={{ position: 'static', marginLeft: 'auto' }}>{tier.label}</span>
            </div>
            <h2 className="d-name">{plant.name}</h2>
            <div className="d-origin">Originaria — {plant.origin}</div>

            <div className="d-price-row">
              <div>
                <div className="mono" style={{ color: 'var(--ink-mute)', marginBottom: 4 }}>Prezzo da</div>
                <div className="d-price">{eur(midPrice)}</div>
              </div>
              <div style={{ marginLeft: 'auto' }} className="d-price-range">
                range {priceRange(plant)}<br />
                in base a dimensione
              </div>
            </div>

            <div className="d-actions">
              {buyable ? (
                <>
                  <div className="d-qty">
                    <button onClick={() => setQty(Math.max(1, qty - 1))} aria-label="Diminuisci quantità"><Icon name="minus" size={14} /></button>
                    <input type="number" value={qty} min="1" max={plant.stock}
                      onChange={(e) => setQty(Math.min(plant.stock, Math.max(1, parseInt(e.target.value) || 1)))} aria-label="Quantità" />
                    <button onClick={() => setQty(Math.min(plant.stock, qty + 1))} disabled={qty >= plant.stock} aria-label="Aumenta quantità"><Icon name="plus" size={14} /></button>
                  </div>
                  <button className={`btn-primary ${added ? 'added' : ''}`} onClick={handleAdd}>
                    {added ? <><Icon name="check" size={16} /> Aggiunta</> : <>Aggiungi al carrello · {eur(midPrice * qty)}</>}
                  </button>
                </>
              ) : (
                <AvvisamiQuandoTorna plant={plant} />
              )}
              <button className={`btn-icon ${saved ? 'on' : ''}`} onClick={() => onSave(plant)} title={saved ? 'Rimuovi dai salvati' : 'Salva tra i preferiti'} aria-label="Salva tra i preferiti">
                <Icon name="heart" size={16} />
              </button>
              <button className="btn-icon" onClick={sharePlant} title="Condividi" aria-label="Condividi questa pianta">
                <Icon name={shared ? 'check' : 'share'} size={16} />
              </button>
            </div>

            <div className="mono" style={{ color: 'var(--ink-mute)', marginTop: 8 }}>
              {!buyable
                ? (plant.status === 'coming_soon'
                    ? 'In arrivo nella prossima edizione · iscriviti alla newsletter per essere avvisato'
                    : 'Momentaneamente esaurito · scrivici per sapere quando torna disponibile')
                : <>{plant.stock <= 5 ? `Ultimi ${plant.stock} esemplari · ` : `${plant.stock} esemplari disponibili · `}Spedizione 3–5 gg</>}
            </div>
          </div>
        </div>

        <div className="d-specs">
          <div className="spec">
            <div className="spec-ico"><Icon name="sun" size={18} /></div>
            <div className="spec-lbl">Luce</div>
            <div className="spec-val">{plant.light}</div>
          </div>
          <div className="spec">
            <div className="spec-ico"><Icon name="droplet" size={18} /></div>
            <div className="spec-lbl">Umidità</div>
            <div className="spec-val">{plant.humidity}</div>
          </div>
          <div className="spec">
            <div className="spec-ico"><Icon name="thermo" size={18} /></div>
            <div className="spec-lbl">Temperatura</div>
            <div className="spec-val">{plant.temp}</div>
          </div>
          <div className="spec">
            <div className="spec-ico"><Icon name="watering" size={18} /></div>
            <div className="spec-lbl">Annaffiatura</div>
            <div className="spec-val">{plant.water}</div>
          </div>
          <div className="spec">
            <div className="spec-ico"><Icon name="soil" size={18} /></div>
            <div className="spec-lbl">Substrato</div>
            <div className="spec-val">{plant.soil}</div>
          </div>
          <div className="spec">
            <div className="spec-ico"><Icon name="propagation" size={18} /></div>
            <div className="spec-lbl">Propagazione</div>
            <div className="spec-val">{plant.prop}</div>
          </div>
        </div>

        <div className="d-tabs">
          {/* La scheda propagazione compare solo se ci sono davvero i passaggi:
              su 11 piante su 23 mostrava un titolo e poi il vuoto. Il metodo di
              propagazione resta comunque visibile fra le condizioni di cura. */}
          {[['cura','Cura & Condizioni'],
            ...((plant.steps || []).length ? [['prop','Propagazione passo-passo']] : []),
            ['note','Info & Spedizione']].map(([k,l]) => (
            <button key={k} className={`d-tab ${tab === k ? 'active' : ''}`} onClick={() => setTab(k)}>{l}</button>
          ))}
        </div>

        <div className="d-content">
          {tab === 'cura' && (
            <div>
              <h3 className="d-section-title">Condizioni ottimali</h3>
              <p style={{ color: 'var(--ink-soft)', maxWidth: '60ch', marginBottom: 20 }}>
                Riproduci le condizioni della sua origine ({plant.origin}) per una crescita regolare. I parametri qui sotto definiscono l'intervallo di comfort: deviazioni prolungate rallentano o compromettono la pianta.
              </p>
              <div className="d-specs" style={{ borderTop: '1px solid var(--line)' }}>
                <div className="spec"><div className="spec-lbl">Luce</div><div className="spec-val">{plant.light}</div></div>
                <div className="spec"><div className="spec-lbl">Annaffiatura</div><div className="spec-val">{plant.water}</div></div>
                <div className="spec"><div className="spec-lbl">Substrato consigliato</div><div className="spec-val">{plant.soil}</div></div>
              </div>
            </div>
          )}
          {tab === 'prop' && (
            <div>
              <h3 className="d-section-title">Passaggi per la propagazione</h3>
              <div className="mono" style={{ color: 'var(--ink-mute)', marginBottom: 8 }}>Metodo: {plant.prop}</div>
              <div className="prop-steps">
                {/* Difensivo: un record senza il campo (ripristino da data.js,
                    modifica manuale del JSON) farebbe fallire il rendering. */}
                {(plant.steps || []).map((s, i) => (
                  <div key={i} className="prop-step">
                    <div className="prop-step-no"></div>
                    <div className="prop-step-txt">{s}</div>
                    <div className="prop-step-time">Fase {i + 1}/{(plant.steps || []).length}</div>
                  </div>
                ))}
              </div>
            </div>
          )}
          {tab === 'note' && (
            <div>
              <h3 className="d-section-title">Note del vivaista</h3>
              <div className="note-box">
                <div className="note-ico"><Icon name="info" size={20} /></div>
                <div className="note-lbl">Osservazioni</div>
                <div className="note-txt">{plant.notes}</div>
              </div>
              <div className="price-break">
                <div>
                  <h4>Prezzo</h4>
                  <div className="v">{priceRange(plant)}</div>
                </div>
                <div>
                  <h4>Spedizione</h4>
                  <div className="v">€7,50</div>
                </div>
                <div className="margin">
                  <h4 style={{ marginBottom: 0 }}>Garanzia attecchimento</h4>
                  <div className="v" style={{ color: 'var(--accent-soft)' }}>30 giorni</div>
                </div>
              </div>
            </div>
          )}
        </div>
      </aside>
    </>
  );
};

// ============ Cart Drawer ============
const CartDrawer = ({ open, onClose, cart, onRemove, onQty, onCheckout }) => {
  const items = cart.map(ci => ({ ...ci, plant: CATALOG.plants.find(p => p.id === ci.id) })).filter(i => i.plant);
  const total = items.reduce((s, i) => s + Math.round((i.plant.priceMin + i.plant.priceMax) / 2) * i.qty, 0);

  return (
    <>
      <div className={`drawer-overlay ${open ? 'open' : ''}`} onClick={onClose} style={{ zIndex: 201 }} />
      <aside className={`cart-drawer ${open ? 'open' : ''}`}>
        <div className="cart-head">
          <h3>Carrello</h3>
          <button className="icon-btn" onClick={onClose}><Icon name="close" size={18} /></button>
        </div>
        {items.length === 0 ? (
          <div className="cart-empty">
            <div style={{ fontFamily: 'var(--serif)', fontSize: '1.4rem', marginBottom: 8 }}>Nessuna pianta ancora</div>
            <div style={{ fontSize: '.85rem' }}>Aggiungi varietà dal catalogo per iniziare.</div>
          </div>
        ) : (
          <div className="cart-items">
            {items.map(i => {
              const price = Math.round((i.plant.priceMin + i.plant.priceMax) / 2);
              return (
                <div key={i.id} className="cart-item">
                  <div className="ci-img"><PlantArt plant={i.plant} /></div>
                  <div>
                    <div className="ci-name">{i.plant.name}</div>
                    <div className="ci-meta">
                      <span>{i.plant.family}</span>
                      <span className="ci-qty">
                        <button onClick={() => onQty(i.id, i.qty - 1)}>−</button>
                        <span>{i.qty}</span>
                        <button onClick={() => onQty(i.id, i.qty + 1)}>+</button>
                      </span>
                    </div>
                    <div className="ci-remove" onClick={() => onRemove(i.id)}>Rimuovi</div>
                  </div>
                  <div className="ci-price">{eur(price * i.qty)}</div>
                </div>
              );
            })}
          </div>
        )}
        <div className="cart-foot">
          <div className="cart-total">
            <span className="lbl">Totale (IVA inclusa)</span>
            <span className="amt">{eur(total)}</span>
          </div>
          <button className="btn-primary" disabled={items.length === 0} style={{ opacity: items.length === 0 ? .5 : 1 }} onClick={onCheckout}>
            Procedi al check-out <Icon name="arrow" size={14} />
          </button>
          <div className="cart-note">Spedizione assicurata con confezione termica · 3–5 giorni lavorativi</div>
        </div>
      </aside>
    </>
  );
};

// ============ Checkout ============
// I dati della carta non passano più da qui: si inseriscono sulla pagina di
// Stripe. Per questo sono state rimosse le funzioni che formattavano e
// validavano numero, scadenza e CVC — tenerle sarebbe stato solo un invito a
// rimettere un form carta sul nostro dominio.

const Checkout = ({ open, onClose, cart, onComplete, auth }) => {
  const [step, setStep] = useState(1); // 1 contact, 2 shipping, 3 payment, 4 success
  const [contact, setContact] = useState({ email: '', firstName: '', lastName: '', phone: '' });
  const [shipping, setShipping] = useState({ address: '', city: '', zip: '', province: '', country: 'Italia' });
  const [payMethod, setPayMethod] = useState('card');
  const [errors, setErrors] = useState({});
  const [processing, setProcessing] = useState(false);
  const [orderError, setOrderError] = useState(null);
  const [orderId, setOrderId] = useState('');
  const [promo, setPromo] = useState('');
  const [promoApplied, setPromoApplied] = useState(null);

  useEffect(() => { if (open) { setStep(1); setErrors({}); setProcessing(false); setOrderError(null); } }, [open]);

  // Se il cliente è loggato, precompila i suoi dati invece di farglieli riscrivere
  useEffect(() => {
    if (!open || !auth?.user) return;
    const [first = '', ...rest] = (auth.user.name || '').split(' ');
    setContact(c => ({
      ...c,
      email: c.email || auth.user.email,
      firstName: c.firstName || first,
      lastName: c.lastName || rest.join(' '),
    }));
  }, [open, auth?.user]);

  const items = cart.map(ci => ({ ...ci, plant: CATALOG.plants.find(p => p.id === ci.id) })).filter(i => i.plant);
  const subtotal = items.reduce((s, i) => s + Math.round((i.plant.priceMin + i.plant.priceMax) / 2) * i.qty, 0);
  const shippingCost = subtotal >= 150 ? 0 : 12;
  const discount = promoApplied ? Math.round(subtotal * promoApplied.pct) : 0;
  const taxBase = subtotal - discount + shippingCost;
  const tax = Math.round(taxBase * 0.22 / 1.22); // IVA inclusa
  const total = taxBase;

  const validateStep = () => {
    const e = {};
    if (step === 1) {
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(contact.email)) e.email = 'Email non valida';
      if (!contact.firstName.trim()) e.firstName = 'Richiesto';
      if (!contact.lastName.trim()) e.lastName = 'Richiesto';
      if (!/^[\d\s+()-]{6,}$/.test(contact.phone)) e.phone = 'Telefono non valido';
    } else if (step === 2) {
      if (!shipping.address.trim()) e.address = 'Richiesto';
      if (!shipping.city.trim()) e.city = 'Richiesto';
      if (!/^\d{5}$/.test(shipping.zip)) e.zip = 'CAP a 5 cifre';
      if (!shipping.province.trim()) e.province = 'Richiesto';
    }
    // Lo step 3 non ha più campi da validare: la carta si inserisce su Stripe.
    setErrors(e);
    return Object.keys(e).length === 0;
  };

  const next = () => { if (validateStep()) setStep(s => s + 1); };
  const back = () => setStep(s => Math.max(1, s - 1));

  const applyPromo = () => {
    const codes = { 'PRIMAVERA10': { pct: 0.1, label: '−10% Primavera' }, 'BENVENUTO': { pct: 0.15, label: '−15% Benvenuto' } };
    const code = promo.trim().toUpperCase();
    if (codes[code]) setPromoApplied({ ...codes[code], code });
    else setPromoApplied({ pct: 0, label: 'Codice non valido', invalid: true });
  };

  const submitPayment = async () => {
    if (!validateStep()) return;
    setProcessing(true);
    setOrderError(null);

    try {
      const res = await fetch('/api/orders', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          items: items.map(i => ({ id: i.id, qty: i.qty })),
          contact,
          shipping,
          payMethod
        })
      });

      const data = await res.json();
      if (!res.ok) {
        // 409 = la disponibilità è cambiata mentre il cliente compilava
        setOrderError({ msg: data.error || 'Errore durante l\'elaborazione dell\'ordine', stock: res.status === 409 });
        return;
      }

      // Il carrello resta finché il pagamento non è confermato: se il cliente
      // annulla su Stripe deve ritrovare le sue piante, non un carrello vuoto.
      if (data.checkoutUrl) {
        sessionStorage.setItem('florilegio-ordine-in-corso', data.id);
        window.location.href = data.checkoutUrl;
        return;
      }

      setOrderId(data.id);
      setStep(4);
    } catch(err) {
      setOrderError({ msg: 'Errore di connessione. Controlla la rete e riprova.' });
    } finally {
      setProcessing(false);
    }
  };

  const handleClose = () => {
    if (step === 4) onComplete();
    onClose();
  };

  if (items.length === 0 && step !== 4) return null;

  return (
    <div className={`checkout-overlay ${open ? 'open' : ''}`}>
      <div className="co-head">
        <div className="logo">
          <div className="logo-mark"><Logo /></div>
          <span>Florilegio</span>
        </div>
        {step < 4 && (
          <div className="co-steps">
            {[[1,'Contatti'],[2,'Spedizione'],[3,'Pagamento']].map(([n,l]) => (
              <div key={n} className={`co-step ${step === n ? 'active' : ''} ${step > n ? 'done' : ''}`}>
                <div className="num">{step > n ? <Icon name="check" size={12} /> : n}</div>
                <span>{l}</span>
              </div>
            ))}
          </div>
        )}
        <button className="close-btn" onClick={handleClose}>
          <Icon name="close" size={14} /> {step === 4 ? 'Torna al catalogo' : 'Annulla'}
        </button>
      </div>

      {step === 4 ? (
        <div className="order-success">
          <div className="success-mark"><Icon name="check" size={36} /></div>
          <h1>Ordine confermato</h1>
          <p className="sub">Grazie {contact.firstName}. Riceverai un'email di conferma a <strong>{contact.email}</strong> con i dettagli e il tracciamento. Le piante saranno preparate dal vivaio nelle prossime 48 ore.</p>
          <div className="order-card">
            <div className="row"><div className="lbl">Numero ordine</div><div className="val order-id">{orderId}</div></div>
            <div className="row"><div className="lbl">Importo addebitato</div><div className="val" style={{ fontFamily: 'var(--serif)', fontSize: '1.4rem' }}>{eur(total)}</div></div>
            <div className="row"><div className="lbl">Metodo</div><div className="val">Pagamento sicuro Stripe</div></div>
            <div className="row"><div className="lbl">Spedizione</div><div className="val">{shipping.address}, {shipping.zip} {shipping.city} ({shipping.province})</div></div>
            <div className="row"><div className="lbl">Consegna stimata</div><div className="val">{new Date(Date.now() + 4*86400000).toLocaleDateString('it-IT', { day: 'numeric', month: 'long' })}</div></div>
          </div>
          <button className="btn-primary" onClick={handleClose} style={{ minWidth: 240 }}>Continua a esplorare</button>
        </div>
      ) : (
      <div className="co-body">
        <div>
          <div className="mono" style={{ color: 'var(--ink-mute)', marginBottom: 8 }}>Step {step} di 3</div>
          <h1 className="co-title">
            {step === 1 && 'I tuoi contatti'}
            {step === 2 && 'Indirizzo di spedizione'}
            {step === 3 && 'Pagamento sicuro'}
          </h1>
          <p className="co-sub">
            {step === 1 && 'Per inviarti la conferma e gli aggiornamenti di spedizione.'}
            {step === 2 && 'Spedizione assicurata in tutta Italia, confezione termica.'}
            {step === 3 && 'Tutte le transazioni sono crittografate. Nessun dato di pagamento è memorizzato sui nostri server.'}
          </p>

          {step === 1 && (
            <div className="co-section">
              <div className="field">
                <label>Email</label>
                <input className={errors.email ? 'error' : ''} type="email" placeholder="nome@dominio.it" value={contact.email} onChange={e => setContact({ ...contact, email: e.target.value })} />
                {errors.email && <span className="err">{errors.email}</span>}
              </div>
              <div className="field-row">
                <div className="field">
                  <label>Nome</label>
                  <input className={errors.firstName ? 'error' : ''} value={contact.firstName} onChange={e => setContact({ ...contact, firstName: e.target.value })} />
                  {errors.firstName && <span className="err">{errors.firstName}</span>}
                </div>
                <div className="field">
                  <label>Cognome</label>
                  <input className={errors.lastName ? 'error' : ''} value={contact.lastName} onChange={e => setContact({ ...contact, lastName: e.target.value })} />
                  {errors.lastName && <span className="err">{errors.lastName}</span>}
                </div>
              </div>
              <div className="field">
                <label>Telefono</label>
                <input className={errors.phone ? 'error' : ''} placeholder="+39 …" value={contact.phone} onChange={e => setContact({ ...contact, phone: e.target.value })} />
                {errors.phone && <span className="err">{errors.phone}</span>}
              </div>
            </div>
          )}

          {step === 2 && (
            <div className="co-section">
              <div className="field">
                <label>Indirizzo</label>
                <input className={errors.address ? 'error' : ''} placeholder="Via, numero civico" value={shipping.address} onChange={e => setShipping({ ...shipping, address: e.target.value })} />
                {errors.address && <span className="err">{errors.address}</span>}
              </div>
              <div className="field-row-3">
                <div className="field">
                  <label>Città</label>
                  <input className={errors.city ? 'error' : ''} value={shipping.city} onChange={e => setShipping({ ...shipping, city: e.target.value })} />
                  {errors.city && <span className="err">{errors.city}</span>}
                </div>
                <div className="field">
                  <label>CAP</label>
                  <input className={errors.zip ? 'error' : ''} maxLength={5} value={shipping.zip} onChange={e => setShipping({ ...shipping, zip: e.target.value.replace(/\D/g, '') })} />
                  {errors.zip && <span className="err">{errors.zip}</span>}
                </div>
                <div className="field">
                  <label>Prov.</label>
                  <input className={errors.province ? 'error' : ''} maxLength={2} placeholder="MI" value={shipping.province} onChange={e => setShipping({ ...shipping, province: e.target.value.toUpperCase() })} />
                  {errors.province && <span className="err">{errors.province}</span>}
                </div>
              </div>
              <div className="field">
                <label>Paese</label>
                <select value={shipping.country} onChange={e => setShipping({ ...shipping, country: e.target.value })}>
                  <option>Italia</option><option>Svizzera</option><option>Francia</option><option>Germania</option><option>Austria</option>
                </select>
              </div>
            </div>
          )}

          {step === 3 && (
            <div className="co-section">
              {/* Nessun campo carta qui: i dati di pagamento si inseriscono
                  sulla pagina di Stripe, non sul nostro sito. */}
              <div className="pay-handoff">
                <div className="pay-handoff-ico"><Icon name="lock" size={22} /></div>
                <h4 className="serif">Pagamento sicuro con Stripe</h4>
                <p>
                  Cliccando qui sotto vieni portato sulla pagina protetta di Stripe per
                  inserire i dati di pagamento. I dati della carta non passano mai dal
                  sito di Florilegio.
                </p>
                <ul className="pay-accept">
                  <li>Carte di credito e debito</li>
                  <li>Apple&nbsp;Pay e Google&nbsp;Pay</li>
                  <li>Autenticazione 3D&nbsp;Secure inclusa</li>
                </ul>
                <p className="pay-handoff-note">
                  Al termine torni automaticamente qui con la conferma dell'ordine.
                </p>
              </div>
            </div>
          )}

          {orderError && (
            <div className="co-error" role="alert">
              <Icon name="alert" size={18} />
              <div>
                <strong>{orderError.stock ? 'Disponibilità cambiata' : 'Ordine non completato'}</strong>
                <p>{orderError.msg}</p>
                {orderError.stock && <p className="co-error-hint">Aggiorna il carrello per continuare: nel frattempo qualcun altro potrebbe aver acquistato l'ultimo esemplare.</p>}
              </div>
            </div>
          )}

          <div className="co-actions">
            {step > 1 ? (
              <button className="btn-back" onClick={back}><Icon name="arrow_left" size={14} /> Indietro</button>
            ) : <div />}
            {step < 3 ? (
              <button className="btn-primary" onClick={next} style={{ minWidth: 220 }}>
                Continua <Icon name="arrow" size={14} />
              </button>
            ) : (
              <button className="btn-primary" onClick={submitPayment} disabled={processing} style={{ minWidth: 240, opacity: processing ? .8 : 1 }}>
                {processing ? <><span className="processing"></span> Elaborazione…</> : <>Paga {eur(total)}</>}
              </button>
            )}
          </div>
        </div>

        {/* Order summary */}
        <aside className="co-summary">
          <h3>Riepilogo</h3>
          {items.map(i => {
            const price = Math.round((i.plant.priceMin + i.plant.priceMax) / 2);
            return (
              <div key={i.id} className="co-line">
                <div className="ci-img"><PlantArt plant={i.plant} /></div>
                <div>
                  <div className="nm">{i.plant.name}</div>
                  <div className="qt">QTÀ {i.qty}</div>
                </div>
                <div className="pr">{eur(price * i.qty)}</div>
              </div>
            );
          })}
          <div className="promo">
            <input placeholder="Codice sconto" value={promo} onChange={e => setPromo(e.target.value)} />
            <button onClick={applyPromo}>Applica</button>
          </div>
          {promoApplied && (
            <div className="applied" style={{ color: promoApplied.invalid ? 'var(--accent)' : 'var(--leaf)', fontFamily: 'var(--mono)', fontSize: '.7rem', letterSpacing: '.1em', marginTop: 6 }}>
              {promoApplied.invalid ? '✕' : <Icon name="check" size={12} />} {promoApplied.label}
            </div>
          )}
          <div className="co-totals">
            <div className="row"><span>Subtotale</span><span>{eur(subtotal)}</span></div>
            {discount > 0 && <div className="row"><span>Sconto</span><span>−{eur(discount)}</span></div>}
            <div className="row"><span>Spedizione</span><span>{shippingCost === 0 ? 'Gratis' : eur(shippingCost)}</span></div>
            <div className="row"><span>di cui IVA (22%)</span><span>{eur(tax)}</span></div>
            <div className="row grand"><span>Totale</span><span className="v">{eur(total)}</span></div>
          </div>
          {subtotal < 150 && (
            <div className="mono" style={{ color: 'var(--ink-mute)', marginTop: 12, fontSize: '.6rem' }}>
              + {eur(150 - subtotal)} per spedizione gratuita
            </div>
          )}
        </aside>
      </div>
      )}
    </div>
  );
};

// ============ Footer ============
const Footer = ({ onNav }) => (
  <footer className="footer" id="footer">
    <div className="foot-grid">
      <div>
        <div className="foot-title">Florilegio<em>.</em></div>
        <p style={{ opacity: .7, maxWidth: '38ch', fontSize: '.9rem' }}>
          Vivaio online di specie esotiche propagate in Italia. Schede tecniche documentate, spedizione termica, garanzia di attecchimento.
        </p>
      </div>
      <div className="foot-col">
        <h5>Catalogo</h5>
        {CATALOG.categories.slice(0, 5).map(c => <a key={c.id} style={{cursor:'pointer'}} onClick={() => onNav?.('Catalogo')}>{c.title}</a>)}
      </div>
      <div className="foot-col">
        <h5>Informazioni</h5>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Propagazione')}>Propagazione</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Materiali')}>Materiali</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Diario')}>Diario del vivaio</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Chi siamo')}>Chi siamo</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Contatti')}>Contatti</a>
      </div>
      <div className="foot-col">
        <h5>Servizio clienti</h5>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('FAQ')}>FAQ</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Ordini')}>Traccia ordine</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Wishlist')}>Wishlist</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Prenotazioni')}>Prenotazioni</a>
        <a style={{cursor:'pointer'}} onClick={() => onNav?.('Contatti')}>Assistenza</a>
      </div>
      <div className="foot-col">
        <h5>Vivaio</h5>
        <p style={{ opacity: .7, fontSize: '.85rem', marginBottom: 12 }}>Vivaio domestico a Milano. Spedizioni il martedì in tutta Italia. Ritiro su appuntamento.</p>
        <a style={{cursor:'pointer', opacity: .8 }}>Instagram · @florilegio.vivaio</a>
        <a style={{cursor:'pointer', opacity: .8 }}>info@florilegio.online</a>
      </div>
    </div>
    <div className="foot-bottom">
      <div style={{ display: 'flex', gap: 18, flexWrap: 'wrap' }}>
        <span>© 2026 Florilegio · Milano</span>
        <a style={{ cursor: 'pointer', opacity: .8 }} onClick={() => onNav?.('Termini')}>Termini</a>
        <a style={{ cursor: 'pointer', opacity: .8 }} onClick={() => onNav?.('Privacy')}>Privacy</a>
        <a style={{ cursor: 'pointer', opacity: .8 }} onClick={() => onNav?.('Resi')}>Resi</a>
      </div>
      <span style={{ opacity: .7 }}>Pagamenti sicuri · Stripe</span>
    </div>
  </footer>
);

// ============ Tweaks Panel ============
const TweaksPanel = ({ settings, onChange }) => (
  <div className="tweaks-panel">
    <h4>Tweaks</h4>
    <div className="tweak-row">
      <label>Palette</label>
      <div className="swatch-group">
        {[
          { k: 'warm', bg: '#f4f0e8', ink: '#1a2018', acc: '#b8502e' },
          { k: 'cool', bg: '#edefe8', ink: '#10201a', acc: '#3a7a5a' },
          { k: 'mono', bg: '#f0efec', ink: '#111', acc: '#c79a3a' },
          { k: 'dusk', bg: '#1a2018', ink: '#f4f0e8', acc: '#d97a56' },
        ].map(p => (
          <div key={p.k} className={`swatch ${settings.palette === p.k ? 'on' : ''}`} style={{ background: `linear-gradient(135deg, ${p.bg} 50%, ${p.acc} 50%)` }} onClick={() => onChange({ palette: p.k })} />
        ))}
      </div>
    </div>
    <div className="tweak-row">
      <label>Titoli</label>
      <div className="font-group">
        {['Instrument Serif','EB Garamond','DM Serif Display'].map(f => (
          <div key={f} className={`font-btn ${settings.font === f ? 'on' : ''}`} onClick={() => onChange({ font: f })}>{f.split(' ')[0]}</div>
        ))}
      </div>
    </div>
    <div className="tweak-row">
      <label>Vista default</label>
      <div className="font-group">
        {['grid','list'].map(v => (
          <div key={v} className={`font-btn ${settings.view === v ? 'on' : ''}`} onClick={() => onChange({ view: v })}>{v === 'grid' ? 'Griglia' : 'Lista'}</div>
        ))}
      </div>
    </div>
    <div className="tweak-row">
      <label>Densità card</label>
      <div className="font-group">
        {['comoda','compatta'].map(d => (
          <div key={d} className={`font-btn ${settings.density === d ? 'on' : ''}`} onClick={() => onChange({ density: d })}>{d}</div>
        ))}
      </div>
    </div>
  </div>
);

// ============ Aste ============
// Conto alla rovescia leggibile, aggiornato ogni secondo
const useCountdown = (endAt) => {
  const [ms, setMs] = useState(() => new Date(endAt) - Date.now());
  useEffect(() => {
    setMs(new Date(endAt) - Date.now());
    const t = setInterval(() => setMs(new Date(endAt) - Date.now()), 1000);
    return () => clearInterval(t);
  }, [endAt]);
  return ms;
};
const formattaResiduo = (ms) => {
  if (ms <= 0) return 'Terminata';
  const s = Math.floor(ms / 1000);
  const g = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60;
  if (g > 0) return `${g}g ${h}h ${m}m`;
  if (h > 0) return `${h}h ${m}m ${sec}s`;
  return `${m}m ${sec}s`;
};

const AstaCard = ({ asta, onOffri, urgente }) => {
  const ms = useCountdown(asta.endAt);
  const finita = ms <= 0;
  const programmata = asta.stato === 'programmata';
  return (
    <article className={`asta-card ${urgente && !finita ? 'urgente' : ''}`}>
      <div className="asta-img">
        {asta.images?.[0]
          ? <img src={asta.images[0]} alt={asta.name} loading="lazy" />
          : <div className="asta-img-ph">🌿</div>}
        <div className={`asta-timer ${urgente && !finita ? 'urgente' : ''}`}>
          {programmata
            ? `Inizia ${new Date(asta.startAt).toLocaleDateString('it-IT', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })}`
            : finita ? 'In chiusura…' : `Chiude tra ${formattaResiduo(ms)}`}
        </div>
      </div>
      <div className="asta-body">
        {asta.family && <div className="card-family">{asta.family}</div>}
        <h3 className="asta-name">{asta.name}</h3>
        <div className="asta-prezzo">
          <div>
            <span className="asta-lbl">{asta.bidCount > 0 ? 'Offerta attuale' : 'Base d\'asta'}</span>
            <div className="asta-cifra">{eur(asta.currentBid || asta.startPrice)}</div>
          </div>
          <div className="asta-meta">
            <div>{asta.bidCount} offert{asta.bidCount === 1 ? 'a' : 'e'}</div>
            {asta.leaderName && <div className="asta-leader">in testa: {asta.leaderName}</div>}
          </div>
        </div>
        {asta.hasReserve && !asta.reserveMet && (
          <div className="asta-riserva">Prezzo di riserva non ancora raggiunto</div>
        )}
        <button className="btn-primary" disabled={programmata || finita} onClick={() => onOffri(asta)}>
          {programmata ? 'Non ancora iniziata' : finita ? 'Terminata' : `Offri da ${eur(asta.minNext)}`}
        </button>
      </div>
    </article>
  );
};

const AstesPage = ({ auth, onLoginNeeded }) => {
  const [aste, setAste] = useState(null);
  const [sel, setSel] = useState(null); // asta su cui si sta offrendo

  const carica = () => fetch('/api/auctions').then(r => r.ok ? r.json() : []).then(setAste).catch(() => setAste([]));
  useEffect(() => { carica(); const t = setInterval(carica, 8000); return () => clearInterval(t); }, []);

  const attive = (aste || []).filter(a => a.stato === 'attiva');
  const prossime = (aste || []).filter(a => a.stato === 'programmata');

  return (
    <main className="page">
      <PageHead
        eyebrow="Sezione · Aste"
        title={<>Aste <em>dal vivaio</em>.</>}
        sub="Esemplari unici e piante da collezione, aggiudicati a chi fa l'offerta più alta. Chi offre nell'ultimo minuto fa slittare la chiusura, così nessuno vince rubando l'ultimo secondo."
      />

      {aste === null && <div className="asta-vuoto">Carico le aste…</div>}
      {aste && attive.length === 0 && prossime.length === 0 && (
        <div className="asta-vuoto">
          <div className="asta-vuoto-ico">🔨</div>
          <h3 className="serif">Nessuna asta in corso</h3>
          <p>Le aste compaiono qui quando ci sono esemplari speciali. Iscriviti alla newsletter per saperlo in anticipo.</p>
        </div>
      )}

      {attive.length > 0 && (
        <div className="asta-grid">
          {attive.map(a => (
            <AstaCard key={a.id} asta={a} urgente={new Date(a.endAt) - Date.now() < 3600000}
              onOffri={(asta) => auth.user ? setSel(asta) : onLoginNeeded()} />
          ))}
        </div>
      )}

      {prossime.length > 0 && (
        <>
          <h2 className="asta-sezione serif">In arrivo</h2>
          <div className="asta-grid">
            {prossime.map(a => (
              <AstaCard key={a.id} asta={a} onOffri={() => {}} />
            ))}
          </div>
        </>
      )}

      {sel && (
        <OffertaModal asta={sel} auth={auth} onClose={() => setSel(null)}
          onFatta={() => { setSel(null); carica(); }} />
      )}
    </main>
  );
};

const OffertaModal = ({ asta: astaIniziale, auth, onClose, onFatta }) => {
  const [asta, setAsta] = useState(astaIniziale);
  const [importo, setImporto] = useState(String(astaIniziale.minNext));
  const [err, setErr] = useState('');
  const [busy, setBusy] = useState(false);
  const [fatto, setFatto] = useState(false);
  const ms = useCountdown(asta.endAt);

  // Tiene aggiornata l'offerta corrente mentre il modale è aperto
  useEffect(() => {
    const t = setInterval(() => {
      fetch(`/api/auctions/${asta.id}`).then(r => r.ok ? r.json() : null).then(d => {
        if (d) { setAsta(d); setImporto(v => Math.max(Number(v) || 0, d.minNext) === d.minNext ? String(d.minNext) : v); }
      }).catch(() => {});
    }, 5000);
    return () => clearInterval(t);
  }, [asta.id]);

  const offri = async (e) => {
    e.preventDefault();
    setErr(''); setBusy(true);
    try {
      const r = await fetch(`/api/auctions/${asta.id}/bid`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },
        body: JSON.stringify({ importo: Math.floor(Number(importo)) }),
      });
      const d = await r.json();
      if (!r.ok) {
        setErr(d.error || 'Offerta non riuscita');
        if (d.minNext) { setAsta(a => ({ ...a, minNext: d.minNext })); setImporto(String(d.minNext)); }
        return;
      }
      setFatto(true);
      setTimeout(onFatta, 2200);
    } catch { setErr('Errore di connessione. Riprova.'); }
    finally { setBusy(false); }
  };

  return (
    <div className="modal-ov" onClick={onClose}>
      <div className="asta-modal" onClick={e => e.stopPropagation()}>
        <button className="modal-x" onClick={onClose}><Icon name="x" size={18} /></button>
        {fatto ? (
          <div className="asta-fatto">
            <div className="pay-result-ico ok"><Icon name="check" size={26} /></div>
            <h3 className="serif">Offerta piazzata</h3>
            <p>Sei in testa a <strong>{eur(Math.floor(Number(importo)))}</strong>. Se qualcuno ti supera ti avviso via email.</p>
          </div>
        ) : (
          <>
            <div className="mono asta-modal-eyebrow">La tua offerta</div>
            <h3 className="serif asta-modal-nome">{asta.name}</h3>
            <div className="asta-modal-stato">
              <div>
                <span className="asta-lbl">{asta.bidCount > 0 ? 'Offerta attuale' : 'Base d\'asta'}</span>
                <div className="asta-cifra">{eur(asta.currentBid || asta.startPrice)}</div>
              </div>
              <div className="asta-modal-timer">{ms <= 0 ? 'In chiusura' : `Chiude tra ${formattaResiduo(ms)}`}</div>
            </div>
            <form onSubmit={offri}>
              <label className="asta-modal-lbl">La tua offerta (minimo {eur(asta.minNext)})</label>
              <div className="asta-input">
                <span>€</span>
                <input type="number" min={asta.minNext} step="1" value={importo}
                  onChange={e => setImporto(e.target.value)} autoFocus />
              </div>
              <div className="asta-rilanci">
                {[0, 1, 2].map(k => {
                  const v = asta.minNext + asta.incremento * k;
                  return <button type="button" key={k} className="asta-rilancio" onClick={() => setImporto(String(v))}>{eur(v)}</button>;
                })}
              </div>
              {err && <div className="auth-error" role="alert">{err}</div>}
              <button type="submit" className="btn-primary" style={{ width: '100%', marginTop: 6 }}
                disabled={busy || ms <= 0}>
                {busy ? 'Invio…' : ms <= 0 ? 'Asta terminata' : `Offri ${eur(Math.floor(Number(importo)) || 0)}`}
              </button>
              <p className="asta-nota">
                Offrendo ti impegni ad acquistare se vinci. Il pagamento avviene solo a fine asta, se sei il migliore offerente.
              </p>
            </form>
          </>
        )}
      </div>
    </div>
  );
};

// ============ App ============
const App = () => {
  const [activeCat, setActiveCat] = useState('all');
  const [query, setQuery] = useState('');
  const [view, setView] = useState('grid');
  const [tierFilter, setTierFilter] = useState('all');
  const [luceFilter, setLuceFilter] = useState('all');
  const [umiditaFilter, setUmiditaFilter] = useState('all');
  const [soloDisponibili, setSoloDisponibili] = useState(false);
  const [guidaAperta, setGuidaAperta] = useState(false);
  const azzeraFiltri = () => {
    setActiveCat('all'); setQuery(''); setTierFilter('all');
    setLuceFilter('all'); setUmiditaFilter('all'); setSoloDisponibili(false);
  };
  const [selected, setSelected] = useState(null);
  const [detailOpen, setDetailOpen] = useState(false);
  const [cart, setCart] = useState(() => {
    try { return JSON.parse(localStorage.getItem('florilegio-cart') || '[]'); } catch { return []; }
  });
  const [cartOpen, setCartOpen] = useState(false);
  const [checkoutOpen, setCheckoutOpen] = useState(false);
  const [saved, setSaved] = useState(() => {
    try { return JSON.parse(localStorage.getItem('florilegio-saved') || '[]'); } catch { return []; }
  });
  const [toast, setToast] = useState(null);
  const [settings, setSettings] = useState({ palette: 'warm', font: 'Instrument Serif', view: 'grid', density: 'comoda' });
  const [activeSection, setActiveSection] = useState('Catalogo');
  const [searchOpen, setSearchOpen] = useState(false);
  const [accountOpen, setAccountOpen] = useState(false);

  // ---- Autenticazione cliente ----
  const [authToken, setAuthToken] = useState(() => localStorage.getItem('florilegio-token') || null);
  const [authUser, setAuthUser] = useState(null);
  const [googleClientId, setGoogleClientId] = useState('');

  useEffect(() => {
    fetch('/api/config').then(r => r.json())
      .then(c => setGoogleClientId(c.googleClientId || ''))
      .catch(() => {});
  }, []);

  // Riconvalida il token salvato: se scaduto o non più valido, esce in silenzio
  useEffect(() => {
    if (!authToken) { setAuthUser(null); return; }
    fetch('/api/auth/me', { headers: { Authorization: `Bearer ${authToken}` } })
      .then(r => r.ok ? r.json() : Promise.reject())
      .then(d => setAuthUser(d.user))
      .catch(() => { localStorage.removeItem('florilegio-token'); setAuthToken(null); setAuthUser(null); });
  }, [authToken]);

  const auth = useMemo(() => ({
    user: authUser, token: authToken, googleClientId,
    login: (token, user) => { localStorage.setItem('florilegio-token', token); setAuthToken(token); setAuthUser(user); },
    logout: () => { localStorage.removeItem('florilegio-token'); setAuthToken(null); setAuthUser(null); },
  }), [authUser, authToken, googleClientId]);

  // ---- Ritorno dalla pagina di pagamento Stripe ----
  // L'esito NON si deduce dall'URL: chiunque potrebbe aprire "?pagamento=ok".
  // Si chiede al server, che sa solo quello che Stripe gli ha confermato via
  // webhook firmato. Se l'incasso non risulta ancora registrato si riprova per
  // qualche secondo, perché il webhook può arrivare poco dopo il redirect.
  const [esitoPagamento, setEsitoPagamento] = useState(null);
  useEffect(() => {
    const q = new URLSearchParams(location.search);
    const ordine = q.get('ordine');
    const esito = q.get('pagamento');
    if (!ordine || !esito) return;
    // Pulisce subito la barra degli indirizzi
    history.replaceState(null, '', location.pathname + location.hash);
    sessionStorage.removeItem('florilegio-ordine-in-corso');

    if (esito === 'annullato') {
      setEsitoPagamento({ stato: 'annullato', id: ordine });
      return;
    }

    let tentativi = 0;
    setEsitoPagamento({ stato: 'verifica', id: ordine });
    const controlla = async () => {
      try {
        const r = await fetch(`/api/orders/${encodeURIComponent(ordine)}/stato`);
        if (r.ok) {
          const d = await r.json();
          if (d.paymentStatus === 'pagato') {
            setEsitoPagamento({ stato: 'pagato', ...d });
            setCart([]); // ora sì: l'incasso è confermato
            return;
          }
        }
      } catch { /* riprova */ }
      if (++tentativi < 8) setTimeout(controlla, 1500);
      else setEsitoPagamento({ stato: 'in_verifica', id: ordine });
    };
    controlla();
  }, []);

  // Router via hash. Le sezioni con spazio ("Chi siamo") arrivano codificate
  // come "Chi%20siamo": senza decodifica non corrispondono mai alla lista e la
  // pagina resta su quella precedente al reload o all'apertura di un link.
  useEffect(() => {
    const apply = () => {
      let h = (location.hash || '#Catalogo').replace('#','');
      try { h = decodeURIComponent(h); } catch { /* hash malformato */ }
      const valid = ['Catalogo','Aste','Propagazione','Diario','Chi siamo','Contatti','Wishlist','FAQ','Ordini','Termini','Privacy','Resi','Ambiente','Bundle','Prenotazioni'];
      if (valid.includes(h)) {
        setActiveSection(h);
        window.scrollTo({ top: 0 });
      }
    };
    apply();
    window.addEventListener('hashchange', apply);
    return () => window.removeEventListener('hashchange', apply);
  }, []);

  const navTo = (s) => { location.hash = encodeURIComponent(s); setActiveSection(s); window.scrollTo({ top: 0 }); };

  useEffect(() => { localStorage.setItem('florilegio-cart', JSON.stringify(cart)); }, [cart]);
  useEffect(() => { localStorage.setItem('florilegio-saved', JSON.stringify(saved)); }, [saved]);



  // Apply settings
  useEffect(() => {
    const root = document.documentElement;
    const palettes = {
      warm: { bg: '#f4f0e8', card: '#ffffff', ink: '#1a2018', inkSoft: '#4a524a', line: '#d8d1c2', lineSoft: '#e8e2d4', accent: '#b8502e', leaf: '#3a5a3a', cream: '#ede4ce', dark: '#1a2018' },
      cool: { bg: '#edefe8', card: '#ffffff', ink: '#10201a', inkSoft: '#3a4a42', line: '#c8d0c2', lineSoft: '#dde2d8', accent: '#3a7a5a', leaf: '#2a5a4a', cream: '#d8e0cc', dark: '#10201a' },
      mono: { bg: '#f0efec', card: '#ffffff', ink: '#111', inkSoft: '#444', line: '#d4d2cc', lineSoft: '#e4e2dc', accent: '#c79a3a', leaf: '#333', cream: '#e0ddd2', dark: '#111' },
      dusk: { bg: '#1a2018', card: '#242c22', ink: '#f4f0e8', inkSoft: '#b8b5a8', line: '#3a4238', lineSoft: '#2a3228', accent: '#d97a56', leaf: '#8aa098', cream: '#3a4238', dark: '#0e1310' },
    };
    const p = palettes[settings.palette];
    root.style.setProperty('--bg', p.bg);
    root.style.setProperty('--bg-card', p.card);
    root.style.setProperty('--ink', p.ink);
    root.style.setProperty('--ink-soft', p.inkSoft);
    root.style.setProperty('--line', p.line);
    root.style.setProperty('--line-soft', p.lineSoft);
    root.style.setProperty('--accent', p.accent);
    root.style.setProperty('--leaf', p.leaf);
    root.style.setProperty('--cream', p.cream);
    root.style.setProperty('--bg-dark', p.dark);
    root.style.setProperty('--serif', `'${settings.font}', Georgia, serif`);
    if (settings.view) setView(settings.view);
  }, [settings]);

  const openDetail = (plant) => { setSelected(plant); setDetailOpen(true); };
  const closeDetail = () => setDetailOpen(false);

  const addToCart = (plant, qty = 1) => {
    setCart(prev => {
      const exist = prev.find(i => i.id === plant.id);
      if (exist) return prev.map(i => i.id === plant.id ? { ...i, qty: i.qty + qty } : i);
      return [...prev, { id: plant.id, qty }];
    });
    setToast(`Aggiunta · ${plant.name}`);
    setTimeout(() => setToast(null), 2000);
  };
  const removeCart = (id) => setCart(c => c.filter(i => i.id !== id));
  const qtyCart = (id, q) => setCart(c => q <= 0 ? c.filter(i => i.id !== id) : c.map(i => i.id === id ? { ...i, qty: q } : i));
  const toggleSave = (plant) => setSaved(s => s.includes(plant.id) ? s.filter(i => i !== plant.id) : [...s, plant.id]);

  const filteredPlants = useMemo(() => {
    const base = CATALOG.plants.filter(p => {
      if (activeCat !== 'all' && p.cat !== activeCat) return false;
      if (tierFilter !== 'all' && p.tier !== tierFilter) return false;
      // Le condizioni di coltivazione sono la domanda vera del cliente:
      // "sopravvive dove vivo io?". I dati c'erano ma non erano filtrabili.
      if (luceFilter !== 'all' && !luciDi(p).includes(luceFilter)) return false;
      if (umiditaFilter !== 'all' && umiditaDi(p) !== umiditaFilter) return false;
      if (soloDisponibili && !(p.status === 'available' && p.stock > 0)) return false;
      return true;
    });
    return cercaPiante(base, query, CATALOG.categories);
  }, [activeCat, query, tierFilter, luceFilter, umiditaFilter, soloDisponibili]);

  const cartCount = cart.reduce((s, i) => s + i.qty, 0);

  return (
    <>
      <TopBar cartCount={cartCount} onCartClick={() => setCartOpen(true)} onLogoClick={() => navTo('Catalogo')} activeSection={activeSection} onNav={navTo} onSearch={() => setSearchOpen(true)} onAccount={() => setAccountOpen(true)} />
      {activeSection === 'Catalogo' && (<>
      <Hero />
      <Toolbar {...{ activeCat, setActiveCat, query, setQuery, view, setView, tierFilter, setTierFilter,
                     luceFilter, setLuceFilter, umiditaFilter, setUmiditaFilter,
                     soloDisponibili, setSoloDisponibili, onAzzera: azzeraFiltri,
                     onGuida: () => setGuidaAperta(true), risultati: filteredPlants.length }} />
      <main className="catalog">
        {activeCat === 'all'
          ? CATALOG.categories.map(cat => {
              const plants = filteredPlants.filter(p => p.cat === cat.id);
              // Con i filtri attivi una sezione può restare senza piante: mostrarne
              // il titolo e poi il vuoto fa sembrare il catalogo rotto.
              if (!plants.length) return null;
              return <CategorySection key={cat.id} cat={cat} plants={plants} view={view} onOpen={openDetail} onQuickAdd={addToCart} />;
            })
          : (() => {
              const cat = CATALOG.categories.find(c => c.id === activeCat);
              return <CategorySection cat={cat} plants={filteredPlants} view={view} onOpen={openDetail} onQuickAdd={addToCart} />;
            })()
        }
        {filteredPlants.length === 0 && (
          <div style={{ padding: '100px 20px', textAlign: 'center' }}>
            <div style={{ fontFamily: 'var(--serif)', fontSize: '2rem', marginBottom: 8 }}>Nessuna pianta trovata</div>
            <div style={{ color: 'var(--ink-mute)', maxWidth: '46ch', margin: '0 auto 24px' }}>
              {soloDisponibili
                ? 'Con questi criteri non c’è nulla di disponibile in questo momento. Prova a togliere “Solo disponibili”: potrai farti avvisare quando le piante tornano.'
                : 'Prova ad allargare i criteri, oppure azzera i filtri e riparti.'}
            </div>
            <button className="btn-primary" onClick={azzeraFiltri}>Azzera i filtri</button>
          </div>
        )}
      </main>
      </>)}
      <GuidaAdatta open={guidaAperta} onClose={() => setGuidaAperta(false)}
        onApplica={(luce, umidita) => {
          // Imposta i filtri invece di mostrare un elenco separato: il cliente
          // resta nel catalogo che conosce e può allargare i criteri da lì.
          setActiveCat('all'); setQuery(''); setTierFilter('all');
          setLuceFilter(luce || 'all'); setUmiditaFilter(umidita || 'all');
        }} />
      {activeSection === 'Propagazione' && <PropagazionePage />}
      {/* Materiali e Galleria erano linkate dal footer e dal menu ma non
          venivano disegnate da nessuna parte: chi ci cliccava finiva su una
          pagina bianca. I componenti esistevano già, mancava il collegamento. */}
      {activeSection === 'Materiali' && <MaterialiPage />}
      {activeSection === 'Galleria' && <GalleryPage />}

      {activeSection === 'Diario' && <DiarioPage />}
      {activeSection === 'Chi siamo' && <ChiSiamoPage />}
      {activeSection === 'Contatti' && <ContattiPage />}
      {activeSection === 'Wishlist' && <WishlistPage saved={saved} onOpenPlant={openDetail} onAdd={(p) => addToCart(p)} onRemove={(p) => toggleSave(p)} onNav={navTo} />}
      {activeSection === 'FAQ' && <FAQPage />}
      {activeSection === 'Ordini' && <OrdiniPage onNav={navTo} />}
      {activeSection === 'Termini' && <TerminiPage />}
      {activeSection === 'Privacy' && <PrivacyPage />}
      {activeSection === 'Resi' && <ResiPage />}
      {activeSection === 'Ambiente' && <AmbientePage onOpenPlant={openDetail} onNav={navTo} />}
      {activeSection === 'Bundle' && <BundlePage onAdd={(b) => { setToast(`Aggiunto · ${b.name}`); setTimeout(() => setToast(null), 1800); }} />}
      {activeSection === 'Aste' && <AstesPage auth={auth} onLoginNeeded={() => setAccountOpen(true)} />}
      {activeSection === 'Prenotazioni' && <PrenotazioniPage onNav={navTo} />}
      {activeSection === 'Catalogo' && <Newsletter />}
      <Footer onNav={navTo} />

      <SearchOverlay open={searchOpen} onClose={() => setSearchOpen(false)} onOpenPlant={openDetail} onNav={navTo} />
      <AccountDrawer open={accountOpen} onClose={() => setAccountOpen(false)} saved={saved} cart={cart} onOpenPlant={openDetail} onNav={navTo} auth={auth} />
      <Detail plant={selected} open={detailOpen} onClose={closeDetail} onAdd={addToCart} saved={selected && saved.includes(selected.id)} onSave={toggleSave} />
      <CartDrawer open={cartOpen} onClose={() => setCartOpen(false)} cart={cart} onRemove={removeCart} onQty={qtyCart} onCheckout={() => { setCartOpen(false); setCheckoutOpen(true); }} />
      <Checkout open={checkoutOpen} onClose={() => setCheckoutOpen(false)} cart={cart} auth={auth} onComplete={() => { setCart([]); setCheckoutOpen(false); }} />

      <div className={`toast ${toast ? 'show' : ''}`}>
        <Icon name="check" size={14} />
        {toast}
      </div>


      {esitoPagamento && (
        <div className="pay-result-overlay" onClick={() => esitoPagamento.stato !== 'verifica' && setEsitoPagamento(null)}>
          <div className="pay-result" onClick={e => e.stopPropagation()}>
            {esitoPagamento.stato === 'verifica' && (
              <>
                <div className="pay-result-ico wait"><span className="processing" /></div>
                <h3 className="serif">Verifico il pagamento…</h3>
                <p>Un istante, sto confermando l'incasso con la banca.</p>
              </>
            )}
            {esitoPagamento.stato === 'pagato' && (
              <>
                <div className="pay-result-ico ok"><Icon name="check" size={26} /></div>
                <h3 className="serif">Ordine confermato</h3>
                <p>
                  Grazie! Ho ricevuto il pagamento di <strong>{eur(esitoPagamento.total)}</strong>.
                  Il numero d'ordine è <strong>{esitoPagamento.id}</strong>: lo trovi anche
                  nell'email di conferma appena inviata.
                </p>
                <p className="pay-result-note">Spedisco il martedì con confezione termica. Ricevi il tracking appena parte.</p>
                <button className="btn-primary" onClick={() => setEsitoPagamento(null)}>Continua</button>
              </>
            )}
            {esitoPagamento.stato === 'in_verifica' && (
              <>
                <div className="pay-result-ico wait"><Icon name="alert" size={24} /></div>
                <h3 className="serif">Pagamento in elaborazione</h3>
                <p>
                  La banca sta ancora confermando l'operazione per l'ordine <strong>{esitoPagamento.id}</strong>.
                  Se l'importo risulta addebitato, l'ordine è valido: riceverai l'email di conferma a breve.
                </p>
                <p className="pay-result-note">Nessun problema se chiudi questa finestra.</p>
                <button className="btn-ghost" onClick={() => setEsitoPagamento(null)}>Chiudi</button>
              </>
            )}
            {esitoPagamento.stato === 'annullato' && (
              <>
                <div className="pay-result-ico ko"><Icon name="close" size={24} /></div>
                <h3 className="serif">Pagamento annullato</h3>
                <p>Non è stato addebitato nulla. Il carrello è ancora al suo posto, puoi riprovare quando vuoi.</p>
                <button className="btn-primary" onClick={() => setEsitoPagamento(null)}>Torna al catalogo</button>
              </>
            )}
          </div>
        </div>
      )}

      <CookieBanner />
    </>
  );
};

// Aggiorna il catalogo statico (data.js) con i dati live del gestionale
// (prezzi, stock, foto, descrizioni). Se la richiesta fallisce, resta
// il catalogo statico già caricato come fallback.
(async () => {
  try {
    const res = await fetch('/api/catalog');
    if (res.ok) {
      const live = await res.json();
      if (live?.plants?.length) window.CATALOG = live;
    }
  } catch { /* offline o API non raggiungibile: resta il catalogo statico */ }
  ReactDOM.createRoot(document.getElementById('root')).render(<App />);
})();
