// pages-shop.jsx — Carrito, checkout, confirmación y cuenta del distribuidor.
// Los totales se calculan SIEMPRE en el servidor (POST /api/orders/validate);
// con WHOLESALE_FLAGS.orders apagado el checkout muestra el aviso fail-soft.

const { useState: useShopState, useEffect: useShopEffect, useMemo: useShopMemo } = React;

// ---------- Validación de totales en servidor ----------
// Devuelve { state: 'off'|'loading'|'ok'|'error', data } según el flag y la respuesta.
function useServerTotals(items, enabled, lang) {
  const [result, setResult] = useShopState({ state: 'off', data: null });

  useShopEffect(() => {
    if (!enabled || !window.WHOLESALE_FLAGS.orders || items.length === 0) {
      setResult({ state: 'off', data: null });
      return;
    }
    let alive = true;
    setResult(r => ({ ...r, state: 'loading' }));
    const timer = setTimeout(async () => {
      try {
        const data = await apiFetch('/api/orders/validate', {
          method: 'POST',
          // Solo sku: el productId guardado en carritos puede ser el id local de
          // data.jsx (≠ id de BD) y el servidor lo prioriza al resolver la línea
          body: { items: items.map(it => ({ sku: it.sku, qty: it.qty, finish: it.finish })), lang },
        });
        if (alive) setResult({ state: 'ok', data });
      } catch {
        if (alive) setResult({ state: 'error', data: null });
      }
    }, 350);
    return () => { alive = false; clearTimeout(timer); };
  }, [JSON.stringify(items.map(it => [it.sku, it.qty, it.finish])), enabled, lang]);

  return result;
}

// ---------- Línea de carrito ----------
function CartLine({ item, lang, cart, navigate, priced }) {
  const t = I18N[lang].shop;
  const key = cartItemKey(item);
  const name = lang === 'en' ? item.nameEn : lang === 'fr' ? item.nameFr : item.name;
  return (
    <div className="cart-line">
      <button
        className="cart-line-thumb"
        onClick={() => item.slug && item.category === 'hat' && navigate({ page: 'product', id: item.slug })}
        style={{ cursor: item.slug && item.category === 'hat' ? 'pointer' : 'default' }}
        aria-label={name}
      >
        <Placeholder label={name} ratio="1/1" src={item.hero} blend />
      </button>
      <div className="cart-line-info">
        <div className="eyebrow muted">{item.sku}</div>
        <h3>{name}</h3>
        {item.finish && (
          <div className="cart-line-finish">
            <span className="eyebrow muted">{t.finish}</span>
            <span className="finish-swatch" style={{ background: item.finish }} />
          </div>
        )}
        <div className="cart-line-min">{t.minQtyNote(item.minQty)}</div>
      </div>
      <div className="cart-line-actions">
        <QtyStepper value={item.qty} min={item.minQty} step={item.step} onChange={(v) => cart.setQty(key, v)} />
        {priced && priced.priced && (
          <div className="cart-line-price">
            {formatCents(priced.unitPriceCents, lang, priced.currency)} / {t.unit}
            <strong> · {formatCents(priced.lineTotalCents, lang, priced.currency)}</strong>
          </div>
        )}
        {priced && !priced.priced && (
          <div className="cart-line-price muted">{t.toQuote}</div>
        )}
        <button className="cart-line-remove" onClick={() => cart.removeItem(key)}>{t.remove} ✕</button>
      </div>
    </div>
  );
}

// ---------- Página: Carrito ----------
function CartPage({ lang, navigate }) {
  const t = I18N[lang].shop;
  const cart = useCart();
  const auth = useAuth();
  const totals = useServerTotals(cart.items, auth.canSeePrices, lang);

  // Lookup de líneas preciadas por el servidor (clave: sku + acabado)
  const pricedByKey = {};
  if (totals.state === 'ok' && totals.data) {
    for (const l of totals.data.items) pricedByKey[(l.sku || '') + '|' + (l.finish || '')] = l;
  }

  return (
    <div className="page-enter" style={{ background: 'var(--parchment)', minHeight: '70vh' }}>
      <section style={{ padding: '80px 0 120px' }}>
        <div className="container" style={{ maxWidth: 980 }}>
          <Ornament />
          <h1 style={{ fontSize: 'clamp(40px, 5vw, 64px)', fontStyle: 'italic', fontWeight: 400, margin: '20px 0 8px' }}>
            {t.cartTitle}
          </h1>
          <p style={{ color: 'var(--muted)', marginBottom: 40 }}>
            {cart.count > 0 ? `${cart.count} SKU · ${t.unitsTotal(cart.totalUnits)}` : ''}
          </p>

          {cart.count === 0 ? (
            <div className="shop-empty">
              <p>{t.cartEmpty}</p>
              <button className="btn btn-primary" onClick={() => navigate({ page: 'sombreros' })}>
                {t.browseCatalog} <span className="arrow" />
              </button>
            </div>
          ) : (
            <>
              <div className="cart-lines">
                {cart.items.map(it => (
                  <CartLine key={cartItemKey(it)} item={it} lang={lang} cart={cart} navigate={navigate}
                    priced={pricedByKey[it.sku + '|' + (it.finish || '')]} />
                ))}
              </div>

              {/* Totales */}
              <div className="cart-summary">
                {totals.state === 'ok' && totals.data && (
                  <>
                    <div className="cart-summary-row">
                      <span>{t.subtotal}</span>
                      <span>{formatCents(totals.data.subtotalCents, lang, totals.data.currency)}</span>
                    </div>
                    <div className="cart-summary-row total">
                      <span>{t.total}</span>
                      <span>{formatCents(totals.data.totalCents, lang, totals.data.currency)}</span>
                    </div>
                    {totals.data.hasUnpriced && (
                      <div className="cart-summary-note">{t.priceOnRequest}</div>
                    )}
                    {totals.data.hasBackorder && (
                      <div className="cart-summary-note">{t.backorderNote}</div>
                    )}
                  </>
                )}
                {totals.state === 'loading' && <div className="cart-summary-note">…</div>}
                {totals.state === 'error' && <div className="cart-summary-note">{t.apiDown}</div>}
                {totals.state === 'off' && (
                  <div className="cart-summary-note">
                    {!auth.user ? t.loginToSeePrices : t.priceOnRequest}
                  </div>
                )}

                <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 24 }}>
                  {auth.user ? (
                    <button className="btn btn-primary" onClick={() => navigate({ page: 'checkout' })}>
                      {t.checkout} <span className="arrow" />
                    </button>
                  ) : (
                    <button className="btn btn-gold" onClick={() => navigate({ page: 'wholesale' })}>
                      {t.loginCta} <span className="arrow" />
                    </button>
                  )}
                  <button className="btn" onClick={() => navigate({ page: 'sombreros' })}>
                    {t.continueShopping}
                  </button>
                </div>
              </div>
            </>
          )}
        </div>
      </section>
    </div>
  );
}

// ---------- Página: Checkout ----------
function CheckoutPage({ lang, navigate }) {
  const t = I18N[lang].shop;
  const cart = useCart();
  const auth = useAuth();
  const totals = useServerTotals(cart.items, auth.canSeePrices, lang);
  const ordersOn = !!window.WHOLESALE_FLAGS.orders;

  const [form, setForm] = useShopState({
    name: '', company: '', address1: '', address2: '', city: '',
    province: 'QC', postal: '', phone: '', note: '',
  });
  const [submitting, setSubmitting] = useShopState(false);
  const [error, setError] = useShopState('');
  const [showQuote, setShowQuote] = useShopState(false);

  // Guard de sesión
  useShopEffect(() => {
    if (auth.status === 'anonymous') navigate({ page: 'wholesale' });
  }, [auth.status]);

  // Prefill desde el perfil (incluye dirección guardada)
  useShopEffect(() => {
    if (auth.user) {
      const u = auth.user;
      setForm(f => ({
        ...f,
        name:     f.name     || u.name     || '',
        company:  f.company  || u.company  || '',
        phone:    f.phone    || u.phone    || '',
        province: u.province && PROVINCES.includes(u.province) ? u.province : f.province,
        address1: f.address1 || u.shipping_address1 || '',
        address2: f.address2 || u.shipping_address2 || '',
        city:     f.city     || u.shipping_city     || '',
        postal:   f.postal   || u.shipping_postal   || '',
      }));
    }
  }, [auth.user && auth.user.id]);

  if (auth.status !== 'authed') return null;
  if (cart.count === 0) {
    return (
      <div className="page-enter" style={{ background: 'var(--parchment)', minHeight: '60vh' }}>
        <section style={{ padding: '100px 0' }}>
          <div className="container shop-empty">
            <p>{I18N[lang].shop.cartEmpty}</p>
            <button className="btn btn-primary" onClick={() => navigate({ page: 'sombreros' })}>
              {I18N[lang].shop.browseCatalog} <span className="arrow" />
            </button>
          </div>
        </section>
      </div>
    );
  }

  const submit = async (e) => {
    e.preventDefault();
    if (!ordersOn || submitting) return;
    setSubmitting(true);
    setError('');
    try {
      const data = await apiFetch('/api/orders', {
        method: 'POST',
        body: {
          items: cart.items.map(it => ({ sku: it.sku, qty: it.qty, finish: it.finish })), // solo sku (ver useServerTotals)
          shipping: {
            name: form.name, company: form.company,
            address1: form.address1, address2: form.address2,
            city: form.city, province: form.province, postal: form.postal,
            country: 'CA', phone: form.phone,
          },
          note: form.note,
          lang,
        },
      });
      cart.clear();
      navigate({ page: 'order-confirmation', num: data.order.orderNumber });
    } catch (err) {
      setError(err.status === 0 ? t.apiDown : err.message);
    } finally {
      setSubmitting(false);
    }
  };

  // Producto sintético para el fallback de cotización mientras Fase 4 no esté desplegada
  const quoteProduct = {
    name: 'Pedido mayorista', nameEn: 'Wholesale order', nameFr: 'Commande en gros',
    sku: cart.items.map(it => `${it.sku}×${it.qty}`).join(', ').slice(0, 120),
  };

  return (
    <div className="page-enter" style={{ background: 'var(--parchment)' }}>
      <section style={{ padding: '80px 0 120px' }}>
        <div className="container" style={{ maxWidth: 1080 }}>
          <Ornament />
          <h1 style={{ fontSize: 'clamp(40px, 5vw, 64px)', fontStyle: 'italic', fontWeight: 400, margin: '20px 0 40px' }}>
            {t.checkout}
          </h1>

          <form onSubmit={submit} className="checkout-grid">
            {/* Envío */}
            <div>
              <h3 className="checkout-section-title">{t.shippingTitle}</h3>
              <div className="form-grid">
                <div className="form-field"><label htmlFor="co-name">{t.fName}</label>
                  <input id="co-name" required value={form.name} onChange={e => setForm({ ...form, name: e.target.value })} />
                </div>
                <div className="form-field"><label htmlFor="co-company">{t.fCompany}</label>
                  <input id="co-company" required value={form.company} onChange={e => setForm({ ...form, company: e.target.value })} />
                </div>
                <div className="form-field full"><label htmlFor="co-addr1">{t.fAddress1}</label>
                  <input id="co-addr1" required value={form.address1} onChange={e => setForm({ ...form, address1: e.target.value })} />
                </div>
                <div className="form-field full"><label htmlFor="co-addr2">{t.fAddress2}</label>
                  <input id="co-addr2" value={form.address2} onChange={e => setForm({ ...form, address2: e.target.value })} />
                </div>
                <div className="form-field"><label htmlFor="co-city">{t.fCity}</label>
                  <input id="co-city" required value={form.city} onChange={e => setForm({ ...form, city: e.target.value })} />
                </div>
                <div className="form-field"><label htmlFor="co-prov">{t.fProvince}</label>
                  <select id="co-prov" value={form.province} onChange={e => setForm({ ...form, province: e.target.value })}>
                    {PROVINCES.map(p => <option key={p} value={p}>{p}</option>)}
                  </select>
                </div>
                <div className="form-field"><label htmlFor="co-postal">{t.fPostal}</label>
                  <input id="co-postal" required value={form.postal} onChange={e => setForm({ ...form, postal: e.target.value })} />
                </div>
                <div className="form-field"><label htmlFor="co-phone">{t.fPhone}</label>
                  <input id="co-phone" required value={form.phone} onChange={e => setForm({ ...form, phone: e.target.value })} />
                </div>
                <div className="form-field full"><label htmlFor="co-note">{t.fNote}</label>
                  <textarea id="co-note" rows={3} value={form.note} onChange={e => setForm({ ...form, note: e.target.value })} style={{ resize: 'vertical' }} />
                </div>
              </div>
            </div>

            {/* Resumen */}
            <div>
              <h3 className="checkout-section-title">{t.orderReview}</h3>
              <div className="checkout-review">
                {cart.items.map(it => {
                  const name = lang === 'en' ? it.nameEn : lang === 'fr' ? it.nameFr : it.name;
                  return (
                    <div key={cartItemKey(it)} className="checkout-review-line">
                      <span className="qty">{it.qty}×</span>
                      <span className="name">{name}</span>
                      <span className="sku">{it.sku}</span>
                    </div>
                  );
                })}
                <div className="cart-summary" style={{ marginTop: 16 }}>
                  {totals.state === 'ok' && totals.data ? (
                    <>
                      <div className="cart-summary-row total">
                        <span>{t.total}</span>
                        <span>{formatCents(totals.data.totalCents, lang, totals.data.currency)}</span>
                      </div>
                      {totals.data.hasUnpriced && (
                        <div className="cart-summary-note">{t.priceOnRequest}</div>
                      )}
                      {totals.data.hasBackorder && (
                        <div className="cart-summary-note">{t.backorderNote}</div>
                      )}
                    </>
                  ) : (
                    <div className="cart-summary-note">{t.priceOnRequest}</div>
                  )}
                </div>
              </div>

              {!ordersOn && (
                <div className="shop-soft-notice">
                  <p>{t.ordersComingSoon}</p>
                  <button type="button" className="btn btn-gold" onClick={() => setShowQuote(true)}>
                    {t.requestQuote} <span className="arrow" />
                  </button>
                </div>
              )}

              {error && <p className="shop-error">{error}</p>}

              <button type="submit" className="btn btn-primary" disabled={!ordersOn || submitting}
                style={{ width: '100%', justifyContent: 'center', marginTop: 20, opacity: ordersOn ? 1 : 0.5 }}>
                {submitting ? t.placing : t.placeOrder} <span className="arrow" />
              </button>
            </div>
          </form>
        </div>
      </section>
      {showQuote && <QuoteModal lang={lang} product={quoteProduct} onClose={() => setShowQuote(false)} />}
    </div>
  );
}

// ---------- Página: Confirmación ----------
function OrderConfirmationPage({ lang, navigate, num }) {
  const t = I18N[lang].shop;
  return (
    <div className="page-enter" style={{ background: 'var(--parchment)', minHeight: '70vh' }}>
      <section style={{ padding: '120px 0' }}>
        <div className="container" style={{ maxWidth: 640, textAlign: 'center' }}>
          <Ornament />
          <h1 style={{ fontSize: 'clamp(40px, 5vw, 60px)', fontStyle: 'italic', fontWeight: 400, margin: '24px 0 16px' }}>
            {t.orderPlaced}
          </h1>
          <div className="eyebrow" style={{ marginBottom: 8 }}>{t.orderNumber}</div>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 28, letterSpacing: '0.12em', color: 'var(--gold-700)', marginBottom: 24 }}>
            {num}
          </div>
          <p style={{ color: 'var(--muted)', marginBottom: 40 }}>{t.invoiceNote}</p>
          <div style={{ display: 'flex', gap: 12, justifyContent: 'center', flexWrap: 'wrap' }}>
            <button className="btn btn-primary" onClick={() => navigate({ page: 'account' })}>
              {t.myOrders} <span className="arrow" />
            </button>
            <button className="btn" onClick={() => navigate({ page: 'sombreros' })}>
              {t.backToCatalog}
            </button>
          </div>
        </div>
      </section>
    </div>
  );
}

// ---------- Cuenta: pedidos ----------
function AccountOrders({ lang, navigate, orderId }) {
  const t = I18N[lang].shop;
  const ordersOn = !!window.WHOLESALE_FLAGS.orders;
  const [state, setState] = useShopState({ loading: ordersOn, items: [], detail: null, error: '' });
  // Retorno desde Square: el hash trae ?paid=1 (el router lo limpia después)
  const [justPaid] = useShopState(() => /[?&]paid=1/.test(window.location.hash));
  const [pay, setPay] = useShopState({ busy: false, error: '' });
  const [dateFrom, setDateFrom] = useShopState('');
  const [dateTo,   setDateTo]   = useShopState('');

  const startPayment = async () => {
    setPay({ busy: true, error: '' });
    try {
      const res = await apiFetch('/api/orders/' + encodeURIComponent(orderId) + '/pay', { method: 'POST' });
      window.location.href = res.url;
    } catch (err) {
      setPay({ busy: false, error: err.status === 0 ? t.apiDown : err.message });
    }
  };

  useShopEffect(() => {
    if (!ordersOn) return;
    let alive = true;
    (async () => {
      try {
        if (orderId) {
          const detail = await apiFetch('/api/orders/' + encodeURIComponent(orderId));
          if (alive) setState(s => ({ ...s, loading: false, detail }));
        } else {
          const data = await apiFetch('/api/orders');
          if (alive) setState(s => ({ ...s, loading: false, items: (data && data.items) || [] }));
        }
      } catch (err) {
        if (alive) setState(s => ({ ...s, loading: false, error: err.status === 0 ? t.apiDown : err.message }));
      }
    })();
    return () => { alive = false; };
  }, [orderId, ordersOn]);

  if (!ordersOn) {
    return <div className="shop-empty"><p>{t.ordersComingSoon}</p></div>;
  }
  if (state.loading) return <div className="shop-empty"><p>…</p></div>;
  if (state.error) return <div className="shop-empty"><p>{state.error}</p></div>;

  if (orderId && state.detail) {
    const o = state.detail;
    return (
      <div>
        <button className="btn" onClick={() => navigate({ page: 'account' })} style={{ marginBottom: 24 }}>← {t.myOrders}</button>
        <h3 style={{ fontSize: 28, fontStyle: 'italic', fontWeight: 400, marginBottom: 4 }}>{o.orderNumber}</h3>
        <span className={`status-pill st-${o.status}`}>{t.status[o.status] || o.status}</span>
        <div className="checkout-review" style={{ marginTop: 24 }}>
          {(o.items || []).map((it, i) => (
            <div key={i} className="checkout-review-line">
              <span className="qty">{it.qty}×</span>
              <span className="name">{it.name}</span>
              <span className="sku">{it.priced === false ? t.toQuote : formatCents(it.lineTotalCents, lang, o.currency)}</span>
            </div>
          ))}
          <div className="cart-summary-row total" style={{ marginTop: 12 }}>
            <span>{t.total}</span>
            <span>{formatCents(o.totalCents, lang, o.currency)}</span>
          </div>
        </div>
        {justPaid && o.status !== 'paid' && (
          <p className="pay-confirming">{t.payConfirming}</p>
        )}
        {!!window.WHOLESALE_FLAGS.payments && o.paymentAvailable && !justPaid && (
          <div className="pay-box">
            <button className="btn btn-primary" onClick={startPayment} disabled={pay.busy}>
              {pay.busy ? '…' : t.payNow}
            </button>
            <p className="muted" style={{ fontSize: 13, marginTop: 8 }}>{t.paySecure}</p>
            {pay.error && <p className="form-error">{pay.error}</p>}
          </div>
        )}
        {(o.history || []).length > 0 && (
          <div style={{ marginTop: 32 }}>
            <div className="eyebrow muted" style={{ marginBottom: 12 }}>{t.statusLabel}</div>
            {o.history.map((h, i) => (
              <div key={i} className="order-history-line">
                <span className={`status-pill st-${h.status}`}>{t.status[h.status] || h.status}</span>
                <span style={{ color: 'var(--muted)', fontSize: 14 }}>{(h.createdAt || h.created_at || '').slice(0, 10)}</span>
              </div>
            ))}
          </div>
        )}
      </div>
    );
  }

  if (state.items.length === 0) {
    return <div className="shop-empty"><p>{t.noOrders}</p></div>;
  }

  const filtered = state.items.filter(o => {
    const d = (o.createdAt || o.created_at || '').slice(0, 10);
    if (dateFrom && d < dateFrom) return false;
    if (dateTo   && d > dateTo)   return false;
    return true;
  });

  return (
    <div>
      <div style={{ display: 'flex', gap: 12, alignItems: 'center', marginBottom: 16, flexWrap: 'wrap' }}>
        <label style={{ fontSize: 13, display: 'flex', gap: 6, alignItems: 'center', color: 'var(--muted)' }}>
          {t.from || 'Desde'}
          <input type="date" value={dateFrom} onChange={e => setDateFrom(e.target.value)}
            style={{ fontFamily: 'var(--font-mono)', fontSize: 13, padding: '4px 8px', border: '1px solid var(--border)', borderRadius: 4 }} />
        </label>
        <label style={{ fontSize: 13, display: 'flex', gap: 6, alignItems: 'center', color: 'var(--muted)' }}>
          {t.to || 'Hasta'}
          <input type="date" value={dateTo} onChange={e => setDateTo(e.target.value)}
            style={{ fontFamily: 'var(--font-mono)', fontSize: 13, padding: '4px 8px', border: '1px solid var(--border)', borderRadius: 4 }} />
        </label>
        {(dateFrom || dateTo) && (
          <button className="btn btn-sm" onClick={() => { setDateFrom(''); setDateTo(''); }}>✕</button>
        )}
      </div>
      {filtered.length === 0 ? <p style={{ color: 'var(--muted)', fontSize: 14 }}>{t.noOrders}</p> : (
        <table className="orders-table">
          <thead>
            <tr><th>{t.orderNumber}</th><th>{t.date}</th><th>{t.itemsCol}</th><th>{t.total}</th><th>{t.statusLabel}</th></tr>
          </thead>
          <tbody>
            {filtered.map(o => (
              <tr key={o.id} onClick={() => navigate({ page: 'account', orderId: String(o.id) })} style={{ cursor: 'pointer' }}>
                <td style={{ fontFamily: 'var(--font-mono)', fontSize: 13 }}>{o.orderNumber}</td>
                <td>{(o.createdAt || o.created_at || '').slice(0, 10)}</td>
                <td>{o.itemCount}</td>
                <td>{formatCents(o.totalCents, lang, o.currency)}</td>
                <td><span className={`status-pill st-${o.status}`}>{t.status[o.status] || o.status}</span></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </div>
  );
}

// ---------- Cuenta: perfil ----------
function AccountProfile({ lang }) {
  const t = I18N[lang].shop;
  const auth = useAuth();
  const u = auth.user || {};
  const [form, setForm] = useShopState({
    name: u.name || '',
    company: u.company || '',
    phone: u.phone || '',
    province: u.province || 'QC',
    shipping_address1: u.shipping_address1 || '',
    shipping_address2: u.shipping_address2 || '',
    shipping_city: u.shipping_city || '',
    shipping_postal: u.shipping_postal || '',
  });
  const [saving, setSaving] = useShopState(false);
  const [msg, setMsg] = useShopState('');

  const f = (key) => ({ value: form[key], onChange: e => setForm({ ...form, [key]: e.target.value }) });

  const save = async (e) => {
    e.preventDefault();
    setSaving(true);
    setMsg('');
    try {
      await apiFetch('/api/auth/me', { method: 'PUT', body: form });
      await auth.refreshUser();
      setMsg(t.saved);
    } catch (err) {
      setMsg(err.status === 0 ? t.apiDown : err.message);
    } finally {
      setSaving(false);
    }
  };

  return (
    <form onSubmit={save} style={{ maxWidth: 560 }}>
      <div className="form-grid">
        <div className="form-field full"><label>{I18N[lang].portal.email}</label>
          <input value={u.email || ''} disabled style={{ opacity: 0.6 }} />
        </div>
        <div className="form-field"><label>{t.fName}</label>
          <input required {...f('name')} />
        </div>
        <div className="form-field"><label>{t.fCompany}</label>
          <input {...f('company')} />
        </div>
        <div className="form-field"><label>{t.fPhone}</label>
          <input {...f('phone')} />
        </div>
        <div className="form-field"><label>{t.fProvince}</label>
          <select value={form.province} onChange={e => setForm({ ...form, province: e.target.value })}>
            {PROVINCES.map(p => <option key={p} value={p}>{p}</option>)}
          </select>
        </div>
        <div className="form-field full" style={{ marginTop: 8, borderTop: '1px solid rgba(27,18,10,0.1)', paddingTop: 16 }}>
          <label style={{ fontWeight: 600, fontSize: 13, letterSpacing: '.05em', textTransform: 'uppercase', color: 'var(--muted)' }}>
            {t.shippingTitle || 'Dirección de envío predeterminada'}
          </label>
        </div>
        <div className="form-field full"><label>{t.fAddress1}</label>
          <input {...f('shipping_address1')} placeholder={t.fAddress1} />
        </div>
        <div className="form-field full"><label>{t.fAddress2}</label>
          <input {...f('shipping_address2')} placeholder={t.fAddress2} />
        </div>
        <div className="form-field"><label>{t.fCity}</label>
          <input {...f('shipping_city')} placeholder={t.fCity} />
        </div>
        <div className="form-field"><label>{t.fPostal}</label>
          <input {...f('shipping_postal')} placeholder={t.fPostal} />
        </div>
      </div>
      {msg && <p className="shop-msg">{msg}</p>}
      <button type="submit" className="btn btn-primary" disabled={saving} style={{ marginTop: 24 }}>
        {t.save} <span className="arrow" />
      </button>
    </form>
  );
}

// ---------- Cuenta: contraseña ----------
function AccountPassword({ lang }) {
  const t = I18N[lang].shop;
  const [form, setForm] = useShopState({ current: '', next: '', repeat: '' });
  const [saving, setSaving] = useShopState(false);
  const [msg, setMsg] = useShopState('');

  const save = async (e) => {
    e.preventDefault();
    setMsg('');
    if (form.next !== form.repeat) { setMsg(t.passwordMismatch); return; }
    setSaving(true);
    try {
      await apiFetch('/api/auth/change-password', {
        method: 'PUT',
        body: { currentPassword: form.current, newPassword: form.next },
      });
      setForm({ current: '', next: '', repeat: '' });
      setMsg(t.passwordChanged);
    } catch (err) {
      setMsg(err.status === 0 ? t.apiDown : err.message);
    } finally {
      setSaving(false);
    }
  };

  return (
    <form onSubmit={save} style={{ maxWidth: 420 }}>
      <div className="form-field" style={{ marginBottom: 20 }}><label>{t.currentPassword}</label>
        <input type="password" required value={form.current} onChange={e => setForm({ ...form, current: e.target.value })} />
      </div>
      <div className="form-field" style={{ marginBottom: 20 }}><label>{t.newPassword}</label>
        <input type="password" required minLength={8} value={form.next} onChange={e => setForm({ ...form, next: e.target.value })} />
      </div>
      <div className="form-field" style={{ marginBottom: 20 }}><label>{t.repeatPassword}</label>
        <input type="password" required minLength={8} value={form.repeat} onChange={e => setForm({ ...form, repeat: e.target.value })} />
      </div>
      {msg && <p className="shop-msg">{msg}</p>}
      <button type="submit" className="btn btn-primary" disabled={saving}>
        {t.save} <span className="arrow" />
      </button>
    </form>
  );
}

// ---------- Cuenta: catálogo PDF ----------
// La descarga necesita Bearer: se baja como blob y se ofrece vía object URL.
function AccountCatalog({ lang }) {
  const t = I18N[lang].shop;
  const [state, setState] = useShopState({ loading: true, pdf: null, blobUrl: null, error: '' });

  useShopEffect(() => {
    let alive = true;
    let createdUrl = null;
    (async () => {
      try {
        const pdf = await apiFetch('/api/catalog');
        if (!alive) return;
        if (!pdf || !pdf.filename) { setState(s => ({ ...s, loading: false, pdf: null })); return; }
        const res = await fetch(API_BASE + '/api/catalog/download', {
          headers: { Authorization: 'Bearer ' + getStoredToken() },
        });
        if (!res.ok) throw new Error();
        const blob = await res.blob();
        createdUrl = URL.createObjectURL(blob);
        if (alive) setState({ loading: false, pdf, blobUrl: createdUrl, error: '' });
      } catch (err) {
        if (alive) setState(s => ({ ...s, loading: false, error: (err && err.status === 0) ? t.apiDown : '' }));
      }
    })();
    return () => { alive = false; if (createdUrl) URL.revokeObjectURL(createdUrl); };
  }, []);

  const download = () => {
    if (!state.blobUrl) return;
    const a = document.createElement('a');
    a.href = state.blobUrl;
    a.download = (state.pdf && state.pdf.original_name) || 'catalogo.pdf';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  };

  if (state.loading) return <div className="shop-empty"><p>…</p></div>;
  if (!state.pdf) return <div className="shop-empty"><p>{state.error || t.noCatalog}</p></div>;

  return (
    <div>
      <div style={{ display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap' }}>
        <button className="btn btn-primary" onClick={download} disabled={!state.blobUrl}>{t.downloadPdf} ↓</button>
        {state.blobUrl && (
          <button className="btn" onClick={() => window.open(state.blobUrl, '_blank', 'noopener')}>{t.openTab} →</button>
        )}
        <span className="eyebrow muted">
          {t.updatedAt}: {(state.pdf.uploaded_at || '').slice(0, 10)}
        </span>
      </div>
    </div>
  );
}

// ---------- Cuenta: promociones ----------
function AccountPromotions({ lang }) {
  const t = I18N[lang].shop;
  const [state, setState] = useShopState({ loading: true, promos: [] });

  useShopEffect(() => {
    let alive = true;
    apiFetch('/api/promotions')
      .then(d => { if (alive) setState({ loading: false, promos: Array.isArray(d) ? d : [] }); })
      .catch(() => { if (alive) setState({ loading: false, promos: [] }); });
    return () => { alive = false; };
  }, []);

  if (state.loading) return <div className="shop-empty"><p>…</p></div>;
  if (state.promos.length === 0) return <div className="shop-empty"><p>{t.noPromos}</p></div>;

  return (
    <div>
      {state.promos.map(p => (
        <div key={p.id} className="acct-promo-card">
          <h3>{p.title}</h3>
          <p>{p.description}</p>
          {p.expires_at && (
            <div className="acct-promo-meta">{t.validUntil}: {(p.expires_at || '').slice(0, 10)}</div>
          )}
          {p.link_url && (
            <a href={p.link_url} target="_blank" rel="noopener noreferrer">
              <button className="btn btn-gold" style={{ marginTop: 14 }}>{t.promoSee} <span className="arrow" /></button>
            </a>
          )}
        </div>
      ))}
    </div>
  );
}

// ---------- Cuenta: soporte ----------
function AccountSupport({ lang }) {
  const t = I18N[lang].shop;
  const settings = usePublicSettings();
  const [messages, setMessages] = useShopState([]);
  const [form, setForm] = useShopState({ subject: '', message: '' });
  const [sent, setSent] = useShopState(false);
  const [sending, setSending] = useShopState(false);
  const [error, setError] = useShopState('');

  const load = () => {
    apiFetch('/api/support')
      .then(d => setMessages(Array.isArray(d) ? d : []))
      .catch(() => {});
  };
  useShopEffect(load, []);

  const submit = async (e) => {
    e.preventDefault();
    setSending(true); setError('');
    try {
      await apiFetch('/api/support', { method: 'POST', body: { subject: form.subject, message: form.message } });
      setSent(true);
      setForm({ subject: '', message: '' });
      load();
      setTimeout(() => setSent(false), 3000);
    } catch (err) {
      setError(err.status === 0 ? t.apiDown : err.message);
    } finally {
      setSending(false);
    }
  };

  return (
    <div className="acct-support">
      <form onSubmit={submit} style={{ marginBottom: 40 }}>
        <div className="form-field">
          <label>{t.supportSubject}</label>
          <input required maxLength={200} value={form.subject} onChange={e => setForm({ ...form, subject: e.target.value })} />
        </div>
        <div className="form-field">
          <label>{t.supportMsg}</label>
          <textarea required rows={4} maxLength={3000} value={form.message} onChange={e => setForm({ ...form, message: e.target.value })} />
        </div>
        {sent && <p className="shop-msg">{t.supportSentOk} ✓</p>}
        {error && <p className="form-error">{error}</p>}
        <button type="submit" className="btn btn-primary" disabled={sending} style={{ marginTop: 8 }}>
          {sending ? '…' : t.supportSend} <span className="arrow" />
        </button>
      </form>

      <div className="eyebrow muted" style={{ marginBottom: 14 }}>{t.myMessages}</div>
      {messages.length === 0 ? (
        <p style={{ color: 'var(--muted)', fontSize: 15, marginBottom: 32 }}>{t.supportNone}</p>
      ) : messages.map(m => (
        <div key={m.id} className="acct-thread">
          <div className="acct-thread-head">{m.subject} · {(m.created_at || '').slice(0, 10)}</div>
          <div className="acct-thread-body">{m.message}</div>
          {m.reply ? (
            <div className="acct-thread-reply">
              <div className="eyebrow muted" style={{ fontSize: 9, marginBottom: 6 }}>
                {t.supportReply}{m.replied_at ? ' · ' + m.replied_at.slice(0, 10) : ''}
              </div>
              {m.reply}
            </div>
          ) : (
            <div className="eyebrow muted" style={{ fontSize: 9 }}>{t.supportPending}</div>
          )}
        </div>
      ))}

      <div className="acct-wa-box">
        <p>{t.supportWaNote}</p>
        <a href={'https://wa.me/' + settings.whatsapp_number} target="_blank" rel="noopener noreferrer">
          <button className="btn" style={{ marginTop: 10 }}>{t.supportWhatsApp} →</button>
        </a>
      </div>
    </div>
  );
}

// ---------- Página: Mi cuenta ----------
function AccountPage({ lang, navigate, orderId }) {
  const t = I18N[lang].shop;
  const tp = I18N[lang].portal;
  const auth = useAuth();
  const [tab, setTab] = useShopState('orders'); // orders | profile | password

  useShopEffect(() => {
    if (auth.status === 'anonymous') navigate({ page: 'wholesale' });
  }, [auth.status]);

  if (auth.status !== 'authed') return null;

  const firstName = (auth.user.name || '').split(' ')[0] || auth.user.email;

  return (
    <div className="page-enter" style={{ background: 'var(--parchment)' }}>
      <section style={{ padding: '80px 0 40px', background: 'var(--ink)', color: 'var(--cream)' }}>
        <div className="container" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 20, flexWrap: 'wrap' }}>
          <div>
            <div className="eyebrow light" style={{ marginBottom: 12 }}>{t.myAccount}</div>
            <h1 style={{ fontSize: 'clamp(36px, 5vw, 56px)', fontStyle: 'italic', fontWeight: 400, color: 'var(--cream)' }}>
              {tp.welcome}, {firstName}.
            </h1>
          </div>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
            {auth.user.role === 'admin' && (
              <a className="btn btn-ghost-light" href="/portal/admin" style={{ textDecoration: 'none' }}>{t.adminPortal}</a>
            )}
            <button onClick={() => { auth.logout(); navigate({ page: 'home' }); }} className="btn btn-ghost-light">
              {tp.signout}
            </button>
          </div>
        </div>
      </section>

      <section style={{ padding: '40px 0 120px' }}>
        <div className="container">
          <div className="account-tabs">
            {[['orders', t.myOrders], ['catalog', t.catalogTab], ['promos', t.promosTab], ['support', t.supportTab], ['profile', t.profile], ['password', t.passwordTab]].map(([id, label]) => (
              <button key={id}
                className={`account-tab ${tab === id ? 'active' : ''}`}
                onClick={() => { setTab(id); if (orderId) navigate({ page: 'account' }); }}
              >{label}</button>
            ))}
          </div>
          <div style={{ marginTop: 36 }}>
            {tab === 'orders' && <AccountOrders lang={lang} navigate={navigate} orderId={orderId} />}
            {tab === 'catalog' && <AccountCatalog lang={lang} />}
            {tab === 'promos' && <AccountPromotions lang={lang} />}
            {tab === 'support' && <AccountSupport lang={lang} />}
            {tab === 'profile' && <AccountProfile lang={lang} />}
            {tab === 'password' && <AccountPassword lang={lang} />}
          </div>
        </div>
      </section>
    </div>
  );
}

Object.assign(window, { CartPage, CheckoutPage, OrderConfirmationPage, AccountPage });
