/* global React, Icon, Logo, Nav, Footer */
const { useState: useStateCk, useRef: useRefCk, useEffect: useEffectRef } = React;

/* ── Rejection reason labels (mirrors operator panel) ─────────── */
const REJECTION_LABELS = {
  numero_incorrecto:  'Número incorrecto',
  no_recibe_recargas: 'No puede recibir recargas',
  numero_no_existe:   'Número no existe / inactivo',
  limite_alcanzado:   'Límite de recargas alcanzado',
  cuenta_suspendida:  'Cuenta suspendida',
  error_tecnico:      'Error técnico del operador',
  otro:               'Otro motivo',
};

/* ── Unique transaction reference ID ─────────────────────────── */
function generateRef() {
  const ts   = Date.now().toString(36).toUpperCase().slice(-7);
  const rand = Math.random().toString(36).replace(/[^a-z]/gi, '').toUpperCase().slice(0, 4);
  return `SMC-${ts}-${rand}`;
}

/* ── Operator panel: encrypt recipient with AES-GCM ─────────── */
async function encryptForOperator(text) {
  const keyHex = window.SM_OPERATOR_ENC_KEY;
  if (!keyHex || keyHex.length < 64) return text; // no key → send plain
  try {
    const keyBytes = new Uint8Array(keyHex.match(/.{2}/g).map(h => parseInt(h, 16)));
    const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-GCM' }, false, ['encrypt']);
    const iv  = crypto.getRandomValues(new Uint8Array(12));
    const ct  = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, new TextEncoder().encode(text));
    const buf = new Uint8Array(iv.length + ct.byteLength);
    buf.set(iv); buf.set(new Uint8Array(ct), iv.length);
    return btoa(String.fromCharCode(...buf));
  } catch { return text; }
}

function maskRecipient(recipient, type) {
  if (type === 'nauta') {
    const u = (recipient || '').split('@')[0];
    return u.slice(0, 2) + '***@nauta.com.cu';
  }
  const digits = (recipient || '').replace(/\D/g, '');
  return '******' + digits.slice(-2);
}

/* ── Determine operator service category ─────────────────────── */
function getOperatorService(type, productName, offerService) {
  if (offerService) return offerService;           // admin overrides via offer.service
  if (type === 'nauta') return 'nauta';
  const n = (productName || '').toLowerCase();
  if (n.includes('dato') || n.includes(' gb') || n.includes('combinad') || n.includes('lte')) return 'datos';
  return 'movil'; // saldo principal + minutos
}

/* ── Send order to operator panel (non-blocking) ────────────── */
let _opSb = null;
async function sendToOperator({ ref, service, recipient, product, amount_cup, bonus_cup, operator_name, callback_url, customer_email }) {
  const url = window.SM_OPERATOR_SUPABASE_URL;
  const key = window.SM_OPERATOR_ANON_KEY;
  if (!url || !key) return; // not configured → skip
  if (!_opSb) _opSb = window.supabase.createClient(url, key);
  const recipient_enc  = await encryptForOperator(recipient);
  const recipient_mask = maskRecipient(recipient, service);
  await _opSb.from('orders').insert({
    ref, service, operator_name,
    recipient_enc, recipient_mask,
    product,
    amount_cup:     Number(amount_cup) || 0,
    bonus_cup:      Number(bonus_cup)  || 0,
    callback_url,
    customer_email: customer_email || null,
    status: 'disponible',
  });
}

/* ── Inline confirm dialog (replaces native confirm()) ────────── */
function useInlineConfirm() {
  const [cfg, setCfg] = useStateCk(null);
  const resolveRef = useRefCk(null);

  const confirm = (message, danger = true) =>
    new Promise(resolve => { resolveRef.current = resolve; setCfg({ message, danger }); });

  const resolve = (val) => { resolveRef.current?.(val); setCfg(null); };

  const dialog = cfg ? (
    <div style={{
      position:'fixed', inset:0, background:'rgba(15,23,42,.55)', backdropFilter:'blur(4px)',
      zIndex:1000, display:'flex', alignItems:'center', justifyContent:'center', padding:20
    }}>
      <div style={{
        background:'#fff', borderRadius:20, padding:'32px 28px', maxWidth:360, width:'100%',
        textAlign:'center', boxShadow:'0 24px 64px rgba(0,0,0,.18)', animation:'authSlideFade .3s ease'
      }}>
        <div style={{
          width:52, height:52, borderRadius:'50%', margin:'0 auto 16px',
          background:cfg.danger?'#fef2f2':'#eff6ff',
          display:'flex', alignItems:'center', justifyContent:'center'
        }}>
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke={cfg.danger?'#ef4444':'#3b82f6'} strokeWidth="2" strokeLinecap="round">
            <path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/>
            <line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>
          </svg>
        </div>
        <p style={{fontSize:15, fontWeight:600, color:'#1A1423', margin:'0 0 22px', lineHeight:1.5}}>{cfg.message}</p>
        <div style={{display:'flex', gap:10, justifyContent:'center'}}>
          <button className="sm-btn sm-btn--ghost" onClick={() => resolve(false)}>Cancelar</button>
          <button
            className="sm-btn sm-btn--primary"
            style={cfg.danger ? {background:'#ef4444', borderColor:'#ef4444'} : {}}
            onClick={() => resolve(true)}
          >
            {cfg.danger ? 'Sí, eliminar' : 'Confirmar'}
          </button>
        </div>
      </div>
    </div>
  ) : null;

  return { confirm, dialog };
}

// ===== Sub-page chrome =====
function SubHero({ crumbs, title, sub }) {
  return (
    <section className="sm-subhero">
      <div className="sm-subhero__inner">
        <div className="sm-crumbs">
          {crumbs.map((c, i) => (
            <React.Fragment key={i}>
              {i > 0 && <span>›</span>}
              {c.href ? <a href={c.href}>{c.label}</a> : <span style={{color:'var(--ink-700)'}}>{c.label}</span>}
            </React.Fragment>
          ))}
        </div>
        <h1 className="sm-subhero__title" dangerouslySetInnerHTML={{__html: title}} />
        {sub && <p className="sm-subhero__sub">{sub}</p>}
      </div>
    </section>
  );
}

// ===== Stepper =====
function Stepper({ step }) {
  const steps = ['Destinatario', 'Oferta', 'Pago', 'Confirmación'];
  return (
    <div className="sm-stepper">
      {steps.map((s, i) => (
        <React.Fragment key={i}>
          <div className={`sm-stepper__item ${i < step ? 'sm-stepper__item--done' : ''} ${i === step ? 'sm-stepper__item--current' : ''}`}>
            <div className="sm-stepper__num">{i < step ? <Icon.Check width="14" height="14" /> : i+1}</div>
            <div className="sm-stepper__label">{s}</div>
          </div>
          {i < steps.length - 1 && <div className={`sm-stepper__line ${i < step ? 'sm-stepper__line--done' : ''}`} />}
        </React.Fragment>
      ))}
    </div>
  );
}

// ===== Order summary card =====
function OrderSummary({ offer, recipient }) {
  const subtotal = offer.price;
  const fee = 0.49;
  const total = (subtotal + fee).toFixed(2);
  return (
    <aside className="sm-summary">
      <h3 className="sm-summary__title">
        Resumen del pedido
        <span className="sm-summary__title-edit">Editar</span>
      </h3>
      <div className="sm-summary__row">
        <span>Para</span>
        <strong>{recipient || '+53 5 234 5678'}</strong>
      </div>
      <div className="sm-summary__row">
        <span>Producto</span>
        <strong>{offer.amount}</strong>
      </div>
      <div className="sm-summary__row">
        <span>Operador</span>
        <strong>Cubacel</strong>
      </div>
      <div className="sm-summary__divider" />
      <div className="sm-summary__row">
        <span>Subtotal</span>
        <strong>${subtotal.toFixed(2)}</strong>
      </div>
      <div className="sm-summary__row">
        <span>Cargo de servicio</span>
        <strong>${fee.toFixed(2)}</strong>
      </div>
      <div className="sm-summary__promo">
        <input placeholder="Código promocional" />
        <button>Aplicar</button>
      </div>
      <div className="sm-summary__divider" />
      <div className="sm-summary__total">
        <span>Total a pagar</span>
        <span className="sm-summary__total-amt">${total}</span>
      </div>
      <div className="sm-summary__guarantee">
        <Icon.Shield width="18" height="18" />
        <div><strong>Garantía 100%.</strong> Si la recarga no llega en 5 minutos, te devolvemos el dinero.</div>
      </div>
    </aside>
  );
}

// ===== Checkout page =====
function CheckoutPage() {
  const [step, setStep] = useStateCk(2); // show payment step by default
  const [pay, setPay] = useStateCk('card');
  const [selOffer, setSelOffer] = useStateCk(0);

  const offers = [
    { amount: '80 minutos nacionales', desc: '35 días · Cubacel', price: 5.99, was: 7.99, badge: 'Oferta' },
    { amount: '40 minutos nacionales', desc: '35 días · Cubacel', price: 3.99 },
    { amount: '500 CUP saldo', desc: '30 días · Cubacel', price: 8.99, badge: 'Popular' },
    { amount: '1000 CUP saldo', desc: '30 días · Cubacel', price: 16.50 },
  ];
  const offer = offers[selOffer];

  return (
    <div className="page-host">
      <Nav />
      <SubHero
        crumbs={[{label:'Inicio', href:'index.html'}, {label:'Recargar'}]}
        title='Completa tu <em>recarga</em>'
        sub='Tres pasos rápidos. Tu familiar la recibe en menos de un minuto.'
      />
      <div className="sm-checkout">
        <div>
          <Stepper step={step} />

          {/* Recipient (collapsed view) */}
          <div className="sm-card" style={{marginBottom:16}}>
            <h3 className="sm-card__title">1. Destinatario</h3>
            <p className="sm-card__sub">Selecciona un contacto reciente o introduce un número nuevo.</p>
            <div className="sm-recents">
              <div className="sm-recent"><div className="sm-recent__avatar">M</div> Mami · +53 5 234 5678</div>
              <div className="sm-recent"><div className="sm-recent__avatar" style={{background:'linear-gradient(135deg,#FF8A65,#FF5722)'}}>P</div> Papi · +53 5 998 1122</div>
              <div className="sm-recent"><div className="sm-recent__avatar" style={{background:'linear-gradient(135deg,#FFB74D,#FF9800)'}}>Y</div> Yuni · +53 5 445 7890</div>
              <div className="sm-recent" style={{borderStyle:'dashed'}}><Icon.Plus width="14" height="14" /> Nuevo</div>
            </div>
            <div className="sm-grid-2">
              <div>
                <label className="sm-field__label">Nombre (opcional)</label>
                <input className="sm-input-base" defaultValue="Mami" />
              </div>
              <div>
                <label className="sm-field__label">Número cubano</label>
                <div className="sm-phone">
                  <span className="sm-phone__prefix"><span className="sm-phone__flag"/> +53</span>
                  <input className="sm-phone__input" defaultValue="5 234 5678" />
                </div>
              </div>
            </div>
          </div>

          {/* Offer */}
          <div className="sm-card" style={{marginBottom:16}}>
            <h3 className="sm-card__title">2. Selecciona la oferta</h3>
            <p className="sm-card__sub">Precios finales. Sin sorpresas en la caja.</p>
            {offers.map((o, i) => (
              <div key={i} className={`sm-offer-row ${selOffer===i?'sm-offer-row--sel':''}`} onClick={()=>setSelOffer(i)}>
                <div className="sm-offer-row__left">
                  <div className="sm-offer-row__radio" />
                  <div>
                    <div className="sm-offer-row__title">{o.amount} {o.badge && <span className="sm-offer__badge" style={{position:'static', marginLeft:8}}>{o.badge}</span>}</div>
                    <div className="sm-offer-row__desc">{o.desc}</div>
                  </div>
                </div>
                <div className="sm-offer-row__right">
                  <div className="sm-offer-row__price">${o.price.toFixed(2)}</div>
                  {o.was && <div className="sm-offer-row__was">${o.was.toFixed(2)}</div>}
                </div>
              </div>
            ))}
          </div>

          {/* Payment */}
          <div className="sm-card">
            <h3 className="sm-card__title">3. Método de pago</h3>
            <p className="sm-card__sub">Cifrado SSL · PCI-DSS compliant</p>
            <div className="sm-pay-grid">
              <div className={`sm-pay ${pay==='card'?'sm-pay--sel':''}`} onClick={()=>setPay('card')}>
                <div className="sm-pay__logo">VISA</div>
                <div className="sm-pay__label">Tarjeta</div>
              </div>
              <div className={`sm-pay ${pay==='paypal'?'sm-pay--sel':''}`} onClick={()=>setPay('paypal')}>
                <div className="sm-pay__logo" style={{color:'#003087'}}>PayPal</div>
                <div className="sm-pay__label">Cuenta PayPal</div>
              </div>
              <div className={`sm-pay ${pay==='apple'?'sm-pay--sel':''}`} onClick={()=>setPay('apple')}>
                <div className="sm-pay__logo">  Pay</div>
                <div className="sm-pay__label">Apple Pay</div>
              </div>
            </div>
            {pay === 'card' && (
              <>
                <label className="sm-field__label">Número de tarjeta</label>
                <input className="sm-input-base" defaultValue="4242 4242 4242 4242" style={{marginBottom:14}} />
                <div className="sm-card-grid">
                  <div>
                    <label className="sm-field__label">Titular</label>
                    <input className="sm-input-base" defaultValue="Carlos Pérez" />
                  </div>
                  <div>
                    <label className="sm-field__label">Caduca</label>
                    <input className="sm-input-base" defaultValue="08/28" />
                  </div>
                  <div>
                    <label className="sm-field__label">CVV</label>
                    <input className="sm-input-base" defaultValue="•••" />
                  </div>
                </div>
              </>
            )}
            <button className="sm-btn sm-btn--primary sm-btn--lg sm-btn--block" style={{marginTop:20}} onClick={()=>window.location.href='success.html'}>
              <Icon.Lock /> Pagar ${(offer.price + 0.49).toFixed(2)} · Recarga inmediata
            </button>
          </div>
        </div>
        <OrderSummary offer={offer} recipient="Mami · +53 5 234 5678" />
      </div>
      <Footer />
    </div>
  );
}

// ===== Success page =====
function SuccessPage() {
  return (
    <div className="page-host">
      <Nav />
      <div className="sm-success anim-rise">
        <div className="sm-success__check">
          <Icon.Check width="40" height="40" />
        </div>
        <h1 className="sm-success__title">¡Recarga <em>enviada</em>!</h1>
        <p className="sm-success__desc">Mami va a recibir 80 minutos en su Cubacel en menos de 60 segundos. Te enviamos el recibo a tu correo.</p>
        <div className="sm-success__receipt">
          <div className="sm-success__receipt-row"><span>Pedido</span><strong>#SMC-48291</strong></div>
          <div className="sm-success__receipt-row"><span>Para</span><strong>+53 5 234 5678</strong></div>
          <div className="sm-success__receipt-row"><span>Producto</span><strong>80 min Cubacel · 35 días</strong></div>
          <div className="sm-success__receipt-row"><span>Pagado</span><strong>$6.48 USD</strong></div>
          <div className="sm-success__receipt-row"><span>Estado</span><strong style={{color:'var(--warm-sage)'}}>● Entregado</strong></div>
        </div>
        <div className="sm-success__actions">
          <a href="dashboard.html" className="sm-btn sm-btn--ghost">Ver mis recargas</a>
          <a href="index.html" className="sm-btn sm-btn--primary">Hacer otra <Icon.Arrow /></a>
        </div>
      </div>
      <Footer />
    </div>
  );
}

// ===== Dashboard =====
const { useEffect: useEffectDash } = React;

const fmtMoney = (n) => '$' + (Number(n)||0).toFixed(2);
const fmtDate = (iso) => { try { const d=new Date(iso); return d.toLocaleString('es',{day:'2-digit',month:'short',hour:'2-digit',minute:'2-digit'}); } catch(e){ return iso; } };
// Extract CUP amount from product name e.g. "250 CUP saldo" → "250 CUP"
const parseCupAmt = (product) => { const m = (product||'').match(/^(\d[\d.,]*)\s*CUP/i); return m ? m[1]+' CUP' : null; };

function DashStat({ label, value, delta }) {
  return (
    <div className="sm-stat-card">
      <div className="sm-stat-card__label">{label}</div>
      <div className="sm-stat-card__num">{value}</div>
      {delta && <div className="sm-stat-card__delta">{delta}</div>}
    </div>
  );
}

function TxList({ items, empty }) {
  if (!items.length) return <div style={{padding:28, textAlign:'center', color:'var(--ink-500)'}}>{empty || 'Sin registros todavía.'}</div>;
  return items.map((t, i) => {
    const cupAmt = parseCupAmt(t.product);
    return (
    <div key={t.id || i} className="sm-tx">
      <div className="sm-tx__icon">
        {t.operator==='Nauta'
          ? <Icon.Wifi width="16" height="16" />
          : <Icon.Phone width="16" height="16" />}
      </div>
      <div>
        <div className="sm-tx__name">{t.recipient_name || t.recipient}</div>
        <div className="sm-tx__sub">
          {t.product}
          {t.ref && <span style={{marginLeft:8,fontFamily:'monospace',fontSize:11,background:'#f1f5f9',padding:'1px 6px',borderRadius:4,color:'#64748b'}}>{t.ref}</span>}
        </div>
      </div>
      <div className="sm-tx__date">{fmtDate(t.created_at)}</div>
      <div className="sm-tx__amt">
        {cupAmt
          ? <><span style={{fontWeight:800}}>{cupAmt}</span><div style={{fontSize:11,color:'var(--ink-500)',marginTop:2}}>Pagado: {fmtMoney(t.total)}</div></>
          : fmtMoney(t.total)
        }
      </div>
      <div className={`sm-tx__status sm-tx__status--${t.status==='ok'?'ok':t.status==='failed'?'failed':'pending'}`}
           style={t.status==='failed'?{color:'#dc2626'}:{}}>
        {t.status==='ok'?'● Entregada':t.status==='failed'?'✕ Fallida':'◌ Pendiente'}
        {t.status==='failed' && t.rejection_reason && (
          <div style={{fontSize:11,marginTop:2,opacity:0.85}}>
            {REJECTION_LABELS[t.rejection_reason] || t.rejection_reason}
          </div>
        )}
      </div>
    </div>
  );});
}

// ---------- Section: Resumen ----------
function SectionResumen({ user, txs, go }) {
  const now = new Date();
  const month = now.getMonth(), year = now.getFullYear();
  const thisMonth = txs.filter(t => { const d=new Date(t.created_at); return d.getMonth()===month && d.getFullYear()===year; });
  const totalThis = thisMonth.reduce((s,t)=>s+Number(t.total||0),0);
  const count = thisMonth.length;
  const ok = thisMonth.filter(t=>t.status==='ok').length;
  const name = user?.first_name || (user?.email ? user.email.split('@')[0] : 'amigo');
  return (
    <>
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Hola, <em>{name}</em></h1>
          <p className="sm-dash__h-sub">Tus recargas y actividad reciente, siempre a mano.</p>
        </div>
        <button className="sm-btn sm-btn--primary sm-btn--lg" onClick={()=>go('nueva')}><Icon.Bolt /> Nueva recarga</button>
      </div>
      <div className="sm-stats-grid">
        <DashStat label="Recargas este mes" value={count} delta={ok+' entregadas'} />
        <DashStat label="Total enviado" value={fmtMoney(totalThis)} delta={count?('Promedio '+fmtMoney(totalThis/count)):'—'} />
        <DashStat label="Total histórico" value={txs.length} delta={fmtMoney(txs.reduce((s,t)=>s+Number(t.total||0),0))+' enviado'} />
      </div>
      <div className="sm-table-card">
        <div className="sm-table-card__head">
          <h3 className="sm-table-card__title">Recargas recientes</h3>
          <button className="sm-btn sm-btn--ghost" onClick={()=>go('historial')}>Ver todo</button>
        </div>
        <TxList items={txs.slice(0,5)} empty="Aún no tienes recargas. ¡Crea la primera!" />
      </div>
    </>
  );
}

// ---------- Section: Nueva recarga ----------
function SectionNueva({ contacts, onCreated, go }) {
  const FALLBACK_OFFERS = {
    movil: [
      { id:'m1', amount:'80 minutos nacionales',  desc:'Duración 35 días', price:5.99, cup:0, bonus:0, service:'movil' },
      { id:'m2', amount:'40 minutos nacionales',  desc:'Duración 35 días', price:3.99, cup:0, bonus:0, service:'movil' },
      { id:'m3', amount:'250 CUP saldo',          desc:'Saldo · 30 días',  price:4.50, cup:250, bonus:0, service:'movil' },
      { id:'m4', amount:'500 CUP saldo',          desc:'Saldo · 30 días',  price:8.99, cup:500, bonus:0, service:'movil' },
    ],
    nauta: [
      { id:'n1', amount:'Nauta Plus 15 días', desc:'Internet ilimitado', price:8.50, cup:0, bonus:0, service:'nauta' },
      { id:'n2', amount:'Nauta 1 GB',         desc:'30 días',            price:4.00, cup:0, bonus:0, service:'nauta' },
      { id:'n3', amount:'Nauta 5 GB',         desc:'30 días',            price:12.00,cup:0, bonus:0, service:'nauta' },
      { id:'n4', amount:'Nauta 10 USD',       desc:'Saldo Nauta',        price:10.00,cup:0, bonus:0, service:'nauta' },
    ],
  };

  const [dbOffers, setDbOffers] = useStateCk(null);
  // Stores pending restore data until DB offers load and we can match by id or name
  const restoreOfferRef = useRefCk(null);

  useEffectRef(() => {
    const sb = window.supabaseClient;
    if (!sb) return;
    sb.from('offers').select('*').eq('active', true).order('type').order('sort_order')
      .then(({ data }) => {
        if (!data || !data.length) return;
        const g = { movil: [], nauta: [] };
        data.forEach(o => {
          g[o.type]?.push({
            id:      o.id,
            amount:  o.name,
            desc:    (o.features || []).map(f => f.join(': ')).join(' · '),
            price:   parseFloat(o.price),
            was:     o.was_price ? parseFloat(o.was_price) : undefined,
            badge:   o.badge,
            cup:     Number(o.cup_value)  || 0,
            bonus:   Number(o.bonus_cup)  || 0,
            service: o.type,
          });
        });
        if (g.movil.length + g.nauta.length > 0) setDbOffers(g);
      }).catch(() => {});
  }, []);

  const OFFERS_LIST = dbOffers || window.OFFERS || FALLBACK_OFFERS;
  const [type, setType]           = useStateCk('movil');
  const [cart, setCart]           = useStateCk([]); // array of selected offer ids
  const [phone, setPhone]         = useStateCk('');
  const [contactId, setContactId] = useStateCk('');
  const [msg, setMsg]             = useStateCk('');
  const [err, setErr]             = useStateCk('');
  const [loading, setLoading]     = useStateCk(false);
  const [restored, setRestored]   = useStateCk(false);

  // ── Restore from localStorage (saved when user clicked "Realizar Recarga" on homepage) ──
  useEffectDash(() => {
    try {
      const raw = localStorage.getItem('sm_recarga');
      if (!raw) return;
      const data = JSON.parse(raw);
      if (!data.savedAt || Date.now() - data.savedAt > 30 * 60 * 1000) {
        localStorage.removeItem('sm_recarga');
        return;
      }
      if (data.phone) setPhone(data.phone);
      if (data.type)  setType(data.type);
      if (data.offerId || data.offerName) {
        const ref = { id: data.offerId, name: data.offerName, type: data.type || 'movil' };
        // Try immediate restore from whatever offers are currently loaded (fallback or DB)
        const list = OFFERS_LIST[ref.type] || [];
        const found = list.find(o => o.id === ref.id) || list.find(o => o.amount === ref.name);
        if (found) {
          setCart([found.id]);        // resolved immediately — no need to store ref
        } else {
          restoreOfferRef.current = ref; // defer to type-change or dbOffers effect
        }
      }
      setRestored(true);
      localStorage.removeItem('sm_recarga');
    } catch (_) {}
  }, []);

  // ── When type changes: reset cart, but try to restore from ref ──
  useEffectDash(() => {
    const list = OFFERS_LIST[type] || [];
    const ref  = restoreOfferRef.current;
    if (ref && ref.type === type) {
      // Try to find by id first (DB offers), then by name (fallback offers with same names)
      const found = list.find(o => o.id === ref.id) || list.find(o => o.amount === ref.name);
      if (found) { setCart([found.id]); restoreOfferRef.current = null; return; }
    }
    setCart(list[0] ? [list[0].id] : []);
  }, [type]); // eslint-disable-line react-hooks/exhaustive-deps

  // ── When DB offers load: consume pending restore ref ──
  useEffectDash(() => {
    if (!dbOffers) return;
    const ref = restoreOfferRef.current;
    if (!ref) return;
    const list = dbOffers[ref.type] || [];
    const found = list.find(o => o.id === ref.id) || list.find(o => o.amount === ref.name);
    if (found) { setType(ref.type); setCart([found.id]); restoreOfferRef.current = null; }
  }, [dbOffers]); // eslint-disable-line react-hooks/exhaustive-deps

  const toggleOffer = (id) =>
    setCart(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]);

  const cartOffers   = cart.map(id => (OFFERS_LIST[type] || []).find(o => o.id === id)).filter(Boolean);
  const subtotal     = cartOffers.reduce((s, o) => s + o.price, 0);
  const fee          = 0.49;
  const total        = subtotal + (cart.length > 0 ? fee : 0);

  const recipientDisplay = (() => {
    const chosen = contacts.find(c => c.id === contactId);
    if (chosen) return chosen.name + ' · ' + chosen.phone;
    if (!phone)  return null;
    return type === 'nauta' ? phone + '@nauta.com.cu' : '+53 ' + phone;
  })();

  const onSubmit = async (e) => {
    e.preventDefault();
    setErr(''); setMsg('');
    if (cart.length === 0) { setErr('Selecciona al menos una oferta.'); return; }
    if (!phone.trim() && !contactId) { setErr('Indica un destinatario o elige un contacto.'); return; }
    if (!contactId) {
      if (type === 'movil' && phone.length !== 8) { setErr('El número cubano debe tener exactamente 8 dígitos.'); return; }
      if (type === 'nauta' && !/^[a-z0-9._-]+$/i.test(phone)) { setErr('Ingresa un usuario Nauta válido (sin @nauta.com.cu).'); return; }
    }
    setLoading(true);
    const session  = await window.SMAuth.session();
    const chosen   = contacts.find(c => c.id === contactId);
    const recipient = chosen
      ? chosen.phone
      : (type === 'nauta' ? `${phone}@nauta.com.cu` : `+53${phone}`);

    for (let i = 0; i < cartOffers.length; i++) {
      const offer      = cartOffers[i];
      const ref        = generateRef();
      const offerFee   = i === 0 ? fee : 0; // fee only on the first item in cart
      const offerTotal = offer.price + offerFee;

      const { error } = await window.supabaseClient.from('transactions').insert({
        user_id:    session.user.id,
        contact_id: chosen?.id || null,
        recipient,
        product:    offer.amount,
        operator:   type === 'nauta' ? 'Nauta' : 'Cubacel',
        amount:     offer.price,
        fee:        offerFee,
        total:      offerTotal,
        status:     'pending',
        ref,
      }).select().single();

      if (error) { setErr('Error al crear la recarga: ' + error.message); setLoading(false); return; }

      const operatorService = getOperatorService(type, offer.amount, offer.service);
      sendToOperator({
        ref,
        service:        operatorService,
        recipient,
        product:        offer.amount,
        amount_cup:     Number(offer.cup)   || 0,
        bonus_cup:      Number(offer.bonus) || 0,
        operator_name:  operatorService === 'nauta' ? 'Nauta' : operatorService === 'datos' ? 'Cubacel Datos' : 'Cubacel',
        callback_url:   `${window.location.origin}/dashboard.html?ref={REF}&status={STATUS}`,
        customer_email: session?.user?.email || null,
      }).catch(() => {});
    }

    setLoading(false);
    const processorUrl = window.SM_PROCESSOR_URL;
    if (processorUrl && cartOffers.length === 1) {
      const ref2      = generateRef();
      const returnUrl = `${window.location.origin}/dashboard.html?status=ok`;
      const failUrl   = `${window.location.origin}/dashboard.html?status=failed`;
      const target    = `${processorUrl}?` + new URLSearchParams({
        recipient,
        product:    cartOffers[0].amount,
        operator:   type === 'nauta' ? 'Nauta' : 'Cubacel',
        amount:     String(cartOffers[0].price),
        total:      String(total),
        return_url: returnUrl,
        fail_url:   failUrl,
      }).toString();
      window.location.href = target;
    } else {
      setMsg(cartOffers.length > 1
        ? `${cartOffers.length} recargas registradas con éxito.`
        : 'Recarga registrada con éxito.');
      onCreated && onCreated();
      setTimeout(() => go('historial'), 1800);
    }
  };

  return (
    <>
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Nueva <em>recarga</em></h1>
          <p className="sm-dash__h-sub">Elige destinatario, selecciona las ofertas y paga.</p>
        </div>
      </div>

      {restored && (
        <div style={{
          display:'flex', alignItems:'center', gap:10,
          background:'#ecfdf5', border:'1px solid #a7f3d0', borderRadius:14,
          padding:'12px 18px', fontSize:13, fontWeight:600, color:'#065f46', marginBottom:20,
        }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
            <circle cx="12" cy="12" r="10"/><polyline points="20 6 9 17 4 12"/>
          </svg>
          Hemos recuperado los datos de tu recarga anterior. Revisa y confirma.
        </div>
      )}

      <div style={{display:'flex', gap:20, alignItems:'flex-start', flexWrap:'wrap'}}>

        {/* ── Form ── */}
        <form onSubmit={onSubmit} className="sm-table-card" style={{flex:'1 1 440px', padding:'24px'}}>

          {/* Type toggle */}
          <div className="sm-flash__toggle" style={{marginBottom:20}}>
            <div className="sm-flash__toggle-indicator" style={{left: type==='movil'?'4px':'calc(50% + 0px)'}}/>
            <button type="button" className={`sm-flash__toggle-btn ${type==='movil'?'sm-flash__toggle-btn--active':''}`} onClick={()=>setType('movil')}><Icon.Phone width="16" height="16"/> Móvil</button>
            <button type="button" className={`sm-flash__toggle-btn ${type==='nauta'?'sm-flash__toggle-btn--active':''}`} onClick={()=>setType('nauta')}><Icon.Wifi width="16" height="16"/> Nauta</button>
          </div>

          {/* Recipient */}
          {contacts.length > 0 && (
            <div className="sm-field">
              <label className="sm-field__label">Contacto guardado (opcional)</label>
              <select className="auth-input" value={contactId} onChange={e=>setContactId(e.target.value)} style={{padding:'12px 14px', borderRadius:12}}>
                <option value="">— Nuevo número —</option>
                {contacts.map(c => <option key={c.id} value={c.id}>{c.name} · {c.phone}</option>)}
              </select>
            </div>
          )}

          {!contactId && (
            <div className="sm-field">
              <label className="sm-field__label">{type==='nauta'?'Correo Nauta a recargar':'Número cubano'}</label>
              {type==='nauta' ? (
                <div className="sm-phone">
                  <input className="sm-phone__input" style={{paddingLeft:18}} placeholder="usuario" value={phone} onChange={e=>setPhone(e.target.value.replace(/\s/g,'').toLowerCase())} autoComplete="off"/>
                  <span className="sm-phone__prefix" style={{order:2, borderLeft:'1px solid #eee', borderRight:'none'}}>@nauta.com.cu</span>
                </div>
              ) : (
                <div className="sm-phone">
                  <span className="sm-phone__prefix">{React.createElement(window.CubaFlagSimple)} +53</span>
                  <input className="sm-phone__input" placeholder="5XXXXXXX" inputMode="numeric" maxLength="8" value={phone} onChange={e=>setPhone(e.target.value.replace(/\D/g,'').slice(0,8))}/>
                </div>
              )}
            </div>
          )}

          {/* Multi-select offer grid */}
          <div className="sm-field">
            <label className="sm-field__label" style={{marginBottom:4}}>
              Ofertas
              <span style={{fontWeight:400, color:'var(--ink-400)', fontSize:12, marginLeft:6}}>— puedes seleccionar varias</span>
            </label>
            <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:10}}>
              {(OFFERS_LIST[type] || []).map(o => {
                const inCart = cart.includes(o.id);
                return (
                  <button type="button" key={o.id} onClick={() => toggleOffer(o.id)} style={{
                    display:'flex', flexDirection:'column', alignItems:'flex-start',
                    padding:'14px 16px 12px', border:'2px solid',
                    borderColor: inCart ? 'var(--brand-600)' : 'var(--cream-200)',
                    borderRadius:14,
                    background: inCart ? 'var(--brand-50,#f0eeff)' : '#fff',
                    cursor:'pointer', transition:'all .2s', textAlign:'left', position:'relative',
                    boxShadow: inCart ? '0 4px 16px rgba(79,61,245,.12)' : 'none',
                  }}>
                    {o.badge && (
                      <span style={{position:'absolute', top:8, right:8, fontSize:10, fontWeight:700,
                        padding:'2px 7px', borderRadius:99, background:'var(--brand-600)', color:'#fff'}}>
                        {o.badge}
                      </span>
                    )}
                    {/* Checkmark indicator */}
                    <div style={{
                      width:18, height:18, borderRadius:'50%', marginBottom:8, flexShrink:0,
                      background: inCart ? 'var(--brand-600)' : 'var(--cream-200)',
                      display:'flex', alignItems:'center', justifyContent:'center',
                      transition:'all .2s',
                    }}>
                      {inCart && <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3" strokeLinecap="round"><polyline points="20 6 9 17 4 12"/></svg>}
                    </div>
                    <div style={{fontSize:13, fontWeight:700, color: inCart ? 'var(--brand-700)' : 'var(--ink-900)', lineHeight:1.3}}>{o.amount}</div>
                    <div style={{fontSize:11, color:'var(--ink-400)', marginTop:3, lineHeight:1.4}}>{o.desc}</div>
                    <div style={{display:'flex', alignItems:'baseline', gap:5, marginTop:10}}>
                      <span style={{fontSize:18, fontWeight:800, color: inCart ? 'var(--brand-600)' : 'var(--ink-900)'}}>${o.price.toFixed(2)}</span>
                      {o.was && <span style={{fontSize:11, color:'var(--ink-400)', textDecoration:'line-through'}}>${o.was.toFixed(2)}</span>}
                    </div>
                  </button>
                );
              })}
            </div>
          </div>

          {err && <div style={{color:'#c62828', background:'#ffebee', padding:'10px 14px', borderRadius:10, fontSize:13, margin:'10px 0'}}>{err}</div>}
          {msg && <div style={{color:'#2e7d32', background:'#e8f5e9', padding:'10px 14px', borderRadius:10, fontSize:13, margin:'10px 0'}}>{msg}</div>}

          <button type="submit" className="sm-btn sm-btn--primary sm-btn--lg" style={{width:'100%', marginTop:14}} disabled={loading || cart.length === 0}>
            {loading
              ? 'Procesando…'
              : cart.length === 0
                ? 'Selecciona al menos una oferta'
                : <><Icon.Bolt/> Confirmar y pagar {fmtMoney(total)}</>
            }
          </button>
        </form>

        {/* ── Preview panel ── */}
        <div style={{flex:'0 0 256px', minWidth:220, display:'flex', flexDirection:'column', gap:14}}>

          {/* Recipient card */}
          <div style={{
            background:'linear-gradient(135deg, var(--brand-700,#3d2fc5), var(--brand-600,#4f3df5))',
            borderRadius:18, padding:'20px 20px 22px', color:'#fff',
          }}>
            <div style={{fontSize:10, fontWeight:700, opacity:.65, textTransform:'uppercase', letterSpacing:'.07em', marginBottom:6}}>Destinatario</div>
            {recipientDisplay
              ? <div style={{fontSize:15, fontWeight:700, wordBreak:'break-all'}}>{recipientDisplay}</div>
              : <div style={{fontSize:13, opacity:.5, fontStyle:'italic'}}>Introduce un número arriba</div>
            }

            <div style={{width:'100%', height:1, background:'rgba(255,255,255,.15)', margin:'16px 0'}}/>

            <div style={{fontSize:10, fontWeight:700, opacity:.65, textTransform:'uppercase', letterSpacing:'.07em', marginBottom:10}}>
              Tu familiar recibirá
            </div>
            {cartOffers.length === 0
              ? <div style={{fontSize:13, opacity:.45, fontStyle:'italic'}}>Elige una oferta →</div>
              : cartOffers.map((o, i) => (
                <div key={i} style={{display:'flex', alignItems:'center', gap:8, marginBottom:7}}>
                  <div style={{
                    width:18, height:18, borderRadius:'50%', flexShrink:0,
                    background:'rgba(255,255,255,.2)',
                    display:'flex', alignItems:'center', justifyContent:'center',
                  }}>
                    <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,.9)" strokeWidth="3" strokeLinecap="round"><polyline points="20 6 9 17 4 12"/></svg>
                  </div>
                  <span style={{fontSize:13, lineHeight:1.3}}>{o.amount}</span>
                  <span style={{marginLeft:'auto', fontSize:13, fontWeight:700, opacity:.85}}>${o.price.toFixed(2)}</span>
                </div>
              ))
            }
          </div>

          {/* Price summary */}
          {cart.length > 0 && (
            <div className="sm-table-card" style={{padding:'16px 18px'}}>
              <div style={{fontSize:10, fontWeight:700, color:'var(--ink-400)', textTransform:'uppercase', letterSpacing:'.07em', marginBottom:12}}>Resumen del pago</div>
              <div style={{display:'flex', justifyContent:'space-between', fontSize:13, color:'var(--ink-500)', marginBottom:6}}>
                <span>{cart.length === 1 ? '1 oferta' : `${cart.length} ofertas`}</span>
                <strong style={{color:'var(--ink-800)'}}>${subtotal.toFixed(2)}</strong>
              </div>
              <div style={{display:'flex', justifyContent:'space-between', fontSize:13, color:'var(--ink-400)', marginBottom:10}}>
                <span>Cargo de servicio</span>
                <span>${fee.toFixed(2)}</span>
              </div>
              <div style={{borderTop:'2px solid var(--cream-200)', paddingTop:10, display:'flex', justifyContent:'space-between', fontSize:18, fontWeight:800}}>
                <span>Total</span>
                <span style={{color:'var(--brand-600)'}}>{fmtMoney(total)}</span>
              </div>
              <div style={{marginTop:12, fontSize:11, color:'var(--ink-400)', display:'flex', alignItems:'center', gap:6}}>
                <Icon.Shield width="11" height="11"/>
                Garantía 100% o reembolso
              </div>
            </div>
          )}
        </div>

      </div>
    </>
  );
}

// ---------- Section: Historial ----------
function SectionHistorial({ txs }) {
  const [filter, setFilter] = useStateCk('all');
  const list = txs.filter(t => filter==='all' || t.status===filter);
  return (
    <>
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Historial de <em>recargas</em></h1>
          <p className="sm-dash__h-sub">Todas las recargas que has enviado.</p>
        </div>
      </div>
      <div className="sm-table-card">
        <div className="sm-table-card__head">
          <h3 className="sm-table-card__title">{list.length} registro{list.length===1?'':'s'}</h3>
          <div className="sm-table-card__filter">
            {['all','ok','pending','failed'].map(f => (
              <button key={f} className={filter===f?'is-active':''} onClick={()=>setFilter(f)}>
                {f==='all'?'Todas':f==='ok'?'Entregadas':f==='pending'?'Pendientes':'Fallidas'}
              </button>
            ))}
          </div>
        </div>
        <TxList items={list} />
      </div>
    </>
  );
}

// ---------- Section: Contactos ----------
function SectionContactos({ contacts, reload }) {
  const [form, setForm] = useStateCk({ name:'', phone:'', nauta_user:'', favorite:false });
  const [err, setErr] = useStateCk('');
  const [saving, setSaving] = useStateCk(false);
  const { confirm, dialog } = useInlineConfirm();

  const add = async (e) => {
    e.preventDefault();
    setErr(''); setSaving(true);
    const session = await window.SMAuth.session();
    const { error } = await window.supabaseClient.from('contacts').insert({
      user_id: session.user.id,
      name: form.name.trim(),
      phone: form.phone.trim(),
      nauta_user: form.nauta_user.trim() || null,
      favorite: !!form.favorite,
    });
    setSaving(false);
    if (error) { setErr(error.message); return; }
    setForm({ name:'', phone:'', nauta_user:'', favorite:false });
    reload();
  };
  const remove = async (id) => {
    const yes = await confirm('¿Eliminar este contacto? Esta acción no se puede deshacer.');
    if (!yes) return;
    await window.supabaseClient.from('contacts').delete().eq('id', id);
    reload();
  };
  const toggleFav = async (c) => {
    await window.supabaseClient.from('contacts').update({ favorite: !c.favorite }).eq('id', c.id);
    reload();
  };

  return (
    <>
      {dialog}
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Mis <em>contactos</em></h1>
          <p className="sm-dash__h-sub">Guarda destinatarios frecuentes para recargar más rápido.</p>
        </div>
      </div>
      <form onSubmit={add} className="sm-table-card" style={{padding:22, marginBottom:20}}>
        <h3 style={{margin:'0 0 14px', fontSize:17}}>Añadir contacto</h3>
        <div className="sm-grid-2" style={{gap:12}}>
          <input className="auth-input" required placeholder="Nombre (ej. Mami)" value={form.name} onChange={e=>setForm({...form, name:e.target.value})} style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5'}}/>
          <input className="auth-input" required placeholder="+53 5 XXX XXXX" value={form.phone} onChange={e=>setForm({...form, phone:e.target.value})} style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5'}}/>
        </div>
        <input className="auth-input" placeholder="Usuario Nauta (opcional)" value={form.nauta_user} onChange={e=>setForm({...form, nauta_user:e.target.value})} style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5', marginTop:12, width:'100%', boxSizing:'border-box'}}/>
        <label className="auth-check" style={{marginTop:12}}>
          <input type="checkbox" checked={form.favorite} onChange={e=>setForm({...form, favorite:e.target.checked})} />
          <span className="auth-check__box"><Icon.Check width="12" height="12"/></span>
          Marcar como favorito
        </label>
        {err && <div style={{color:'#c62828', marginTop:10, fontSize:13}}>{err}</div>}
        <button className="sm-btn sm-btn--primary" style={{marginTop:14}} disabled={saving}>{saving?'Guardando…':<><Icon.Plus/> Guardar contacto</>}</button>
      </form>

      <div className="sm-table-card">
        <div className="sm-table-card__head"><h3 className="sm-table-card__title">{contacts.length} contacto{contacts.length===1?'':'s'}</h3></div>
        {contacts.length===0 ? <div style={{padding:28, textAlign:'center', color:'var(--ink-500)'}}>Aún no tienes contactos guardados.</div> :
          contacts.map(c => (
            <div key={c.id} className="sm-tx">
              <div className="sm-tx__icon"><Icon.Phone width="16" height="16"/></div>
              <div>
                <div className="sm-tx__name">{c.name} {c.favorite && <span style={{color:'#f5a623'}}>★</span>}</div>
                <div className="sm-tx__sub">{c.phone}{c.nauta_user?' · '+c.nauta_user:''}</div>
              </div>
              <div></div>
              <button className="sm-btn sm-btn--ghost" onClick={()=>toggleFav(c)} style={{padding:'6px 12px'}}>{c.favorite?'Quitar ★':'Favorito'}</button>
              <button className="sm-btn sm-btn--ghost" onClick={()=>remove(c.id)} style={{padding:'6px 12px', color:'#c62828'}}>Eliminar</button>
            </div>
          ))
        }
      </div>
    </>
  );
}

// ---------- Section: Métodos de pago ----------
function SectionPagos({ methods, reload }) {
  const [form, setForm] = useStateCk({ number:'', exp:'', cvc:'', holder:'' });
  const [err, setErr] = useStateCk(''); const [saving, setSaving] = useStateCk(false);
  const { confirm: confirmDel, dialog: dialogDel } = useInlineConfirm();

  const detectBrand = (num) => {
    const n = (num||'').replace(/\s/g,'');
    if (/^4/.test(n)) return 'visa';
    if (/^5[1-5]/.test(n) || /^2[2-7]/.test(n)) return 'mastercard';
    if (/^3[47]/.test(n)) return 'amex';
    return 'card';
  };
  const add = async (e) => {
    e.preventDefault();
    setErr(''); setSaving(true);
    const num = form.number.replace(/\s/g,'');
    if (num.length < 13) { setErr('Número de tarjeta inválido.'); setSaving(false); return; }
    const [mm, yy] = form.exp.split('/').map(s=>s.trim());
    const month = parseInt(mm,10), year = parseInt(yy,10);
    if (!month || month<1 || month>12 || !year) { setErr('Fecha de expiración inválida (MM/AA).'); setSaving(false); return; }
    const fullYear = year < 100 ? 2000+year : year;
    const session = await window.SMAuth.session();
    // NOTE: we only store last4, brand, exp. NEVER store PAN or CVC.
    const { error } = await window.supabaseClient.from('payment_methods').insert({
      user_id: session.user.id,
      brand: detectBrand(num),
      last4: num.slice(-4),
      exp_month: month, exp_year: fullYear,
      holder: form.holder.trim(),
      is_default: methods.length===0,
    });
    setSaving(false);
    if (error) { setErr(error.message); return; }
    setForm({ number:'', exp:'', cvc:'', holder:'' });
    reload();
  };
  const remove = async (id) => {
    const yes = await confirmDel('¿Eliminar esta tarjeta? Tendrás que volver a añadirla si la necesitas.');
    if (!yes) return;
    await window.supabaseClient.from('payment_methods').delete().eq('id', id);
    reload();
  };
  const setDefault = async (id) => {
    const session = await window.SMAuth.session();
    await window.supabaseClient.from('payment_methods').update({ is_default:false }).eq('user_id', session.user.id);
    await window.supabaseClient.from('payment_methods').update({ is_default:true }).eq('id', id);
    reload();
  };

  return (
    <>
      {dialogDel}
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Métodos de <em>pago</em></h1>
          <p className="sm-dash__h-sub">Solo se guardan los últimos 4 dígitos y el vencimiento. El número completo y CVC nunca se almacenan.</p>
        </div>
      </div>

      <form onSubmit={add} className="sm-table-card" style={{padding:22, marginBottom:20}}>
        <h3 style={{margin:'0 0 14px', fontSize:17}}>Añadir tarjeta</h3>
        <input required placeholder="Nombre del titular" value={form.holder} onChange={e=>setForm({...form, holder:e.target.value})} style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5', width:'100%', boxSizing:'border-box', marginBottom:12}}/>
        <input required placeholder="Número (solo se guardan los últimos 4)" value={form.number} onChange={e=>setForm({...form, number:e.target.value.replace(/[^0-9\s]/g,'')})} maxLength="23" style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5', width:'100%', boxSizing:'border-box', marginBottom:12, fontFamily:'JetBrains Mono, monospace'}}/>
        <div className="sm-grid-2" style={{gap:12}}>
          <input required placeholder="MM/AA" value={form.exp} onChange={e=>setForm({...form, exp:e.target.value})} maxLength="7" style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5'}}/>
          <input required placeholder="CVC (no se guarda)" value={form.cvc} onChange={e=>setForm({...form, cvc:e.target.value.replace(/\D/g,'')})} maxLength="4" type="password" style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5'}}/>
        </div>
        {err && <div style={{color:'#c62828', marginTop:10, fontSize:13}}>{err}</div>}
        <button className="sm-btn sm-btn--primary" style={{marginTop:14}} disabled={saving}>{saving?'Guardando…':<><Icon.Shield/> Guardar tarjeta</>}</button>
      </form>

      <div className="sm-table-card">
        <div className="sm-table-card__head"><h3 className="sm-table-card__title">{methods.length} tarjeta{methods.length===1?'':'s'}</h3></div>
        {methods.length===0 ? <div style={{padding:28, textAlign:'center', color:'var(--ink-500)'}}>No tienes métodos de pago guardados.</div> :
          methods.map(m => (
            <div key={m.id} className="sm-tx">
              <div className="sm-tx__icon"><Icon.Lock width="16" height="16"/></div>
              <div>
                <div className="sm-tx__name">{m.brand.toUpperCase()} •••• {m.last4} {m.is_default && <span style={{color:'var(--brand-600)', fontSize:12, marginLeft:6}}>PRINCIPAL</span>}</div>
                <div className="sm-tx__sub">{m.holder} · Vence {String(m.exp_month).padStart(2,'0')}/{String(m.exp_year).slice(-2)}</div>
              </div>
              <div></div>
              {!m.is_default && <button className="sm-btn sm-btn--ghost" onClick={()=>setDefault(m.id)} style={{padding:'6px 12px'}}>Hacer principal</button>}
              <button className="sm-btn sm-btn--ghost" onClick={()=>remove(m.id)} style={{padding:'6px 12px', color:'#c62828'}}>Eliminar</button>
            </div>
          ))
        }
      </div>
    </>
  );
}

// ---------- Section: Seguridad ----------
function SectionSeguridad({ user }) {
  const [pw, setPw] = useStateCk(''); const [pw2, setPw2] = useStateCk('');
  const [msg, setMsg] = useStateCk(''); const [err, setErr] = useStateCk(''); const [loading, setLoading] = useStateCk(false);
  const rules = {
    length: pw.length >= 8,
    upper: /[A-Z]/.test(pw),
    number: /[0-9]/.test(pw),
    symbol: /[^A-Za-z0-9]/.test(pw),
  };
  const score = Object.values(rules).filter(Boolean).length;

  const onChangePw = async (e) => {
    e.preventDefault();
    setErr(''); setMsg('');
    if (pw !== pw2) { setErr('Las contraseñas no coinciden.'); return; }
    if (score < 3) { setErr('Elige una contraseña más fuerte (mínimo 3 reglas).'); return; }
    setLoading(true);
    const r = await window.SMAuth.updatePassword(pw);
    setLoading(false);
    if (r.ok) { setMsg('Contraseña actualizada correctamente.'); setPw(''); setPw2(''); }
    else setErr(r.error);
  };

  const sendReset = async () => {
    setErr(''); setMsg('');
    const r = await window.SMAuth.resetPassword(user.email);
    if (r.ok) setMsg('Te enviamos un enlace para restablecer la contraseña.');
    else setErr(r.error);
  };

  return (
    <>
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Seguridad de la <em>cuenta</em></h1>
          <p className="sm-dash__h-sub">Controla el acceso y la contraseña de tu cuenta.</p>
        </div>
      </div>

      <div className="sm-table-card" style={{padding:22, marginBottom:20}}>
        <h3 style={{margin:'0 0 8px', fontSize:17}}>Identidad</h3>
        <div style={{fontSize:14, color:'var(--ink-700)'}}>Correo: <strong>{user.email}</strong></div>
        <div style={{fontSize:13, color:'var(--ink-500)', marginTop:6}}>{user.email_confirmed_at ? '✔ Correo verificado' : '⚠ Correo sin verificar'}</div>
      </div>

      <form onSubmit={onChangePw} className="sm-table-card" style={{padding:22, marginBottom:20}}>
        <h3 style={{margin:'0 0 14px', fontSize:17}}>Cambiar contraseña</h3>
        <input type="password" required placeholder="Nueva contraseña" value={pw} onChange={e=>setPw(e.target.value)} style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5', width:'100%', boxSizing:'border-box', marginBottom:12}}/>
        <input type="password" required placeholder="Repetir nueva contraseña" value={pw2} onChange={e=>setPw2(e.target.value)} style={{padding:'12px 14px', borderRadius:12, border:'1px solid #e5e5e5', width:'100%', boxSizing:'border-box', marginBottom:12}}/>
        <div className="auth-strength">
          {[0,1,2,3].map(i => <div key={i} className={`auth-strength__bar ${i < score ? 'is-'+score : ''}`}/>)}
        </div>
        <div className="auth-rules" style={{marginTop:10}}>
          <div className={`auth-rule ${rules.length?'auth-rule--ok':''}`}><span className="auth-rule__dot"><Icon.Check width="9" height="9"/></span>8+ caracteres</div>
          <div className={`auth-rule ${rules.upper?'auth-rule--ok':''}`}><span className="auth-rule__dot"><Icon.Check width="9" height="9"/></span>Una mayúscula</div>
          <div className={`auth-rule ${rules.number?'auth-rule--ok':''}`}><span className="auth-rule__dot"><Icon.Check width="9" height="9"/></span>Un número</div>
          <div className={`auth-rule ${rules.symbol?'auth-rule--ok':''}`}><span className="auth-rule__dot"><Icon.Check width="9" height="9"/></span>Un símbolo</div>
        </div>
        {err && <div style={{color:'#c62828', marginTop:10, fontSize:13}}>{err}</div>}
        {msg && <div style={{color:'#2e7d32', marginTop:10, fontSize:13}}>{msg}</div>}
        <button className="sm-btn sm-btn--primary" style={{marginTop:14}} disabled={loading}>{loading?'Actualizando…':<><Icon.Lock/> Actualizar contraseña</>}</button>
      </form>

      <div className="sm-table-card" style={{padding:22}}>
        <h3 style={{margin:'0 0 8px', fontSize:17}}>¿Olvidaste tu contraseña?</h3>
        <p style={{fontSize:14, color:'var(--ink-500)', marginBottom:14}}>Te enviaremos un enlace seguro por correo para restablecerla.</p>
        <button type="button" className="sm-btn sm-btn--ghost" onClick={sendReset}><Icon.Send/> Enviar enlace de reset</button>
      </div>
    </>
  );
}

// ---------- Section: Notificaciones ----------
function SectionNotificaciones({ prefs, setPrefs }) {
  const [saving, setSaving] = useStateCk(false); const [msg, setMsg] = useStateCk('');
  const toggle = async (key) => {
    const next = { ...prefs, [key]: !prefs[key] };
    setPrefs(next); setSaving(true);
    const session = await window.SMAuth.session();
    await window.supabaseClient.from('notification_prefs').upsert({ user_id: session.user.id, ...next, updated_at: new Date().toISOString() });
    setSaving(false); setMsg('Preferencias guardadas'); setTimeout(()=>setMsg(''), 1500);
  };

  const Row = ({ k, title, desc }) => (
    <label style={{display:'flex', alignItems:'center', gap:14, padding:'16px 0', borderBottom:'1px solid #eee', cursor:'pointer'}}>
      <input type="checkbox" checked={!!prefs[k]} onChange={()=>toggle(k)} style={{width:20, height:20}}/>
      <div>
        <div style={{fontWeight:600, fontSize:15}}>{title}</div>
        <div style={{fontSize:13, color:'var(--ink-500)'}}>{desc}</div>
      </div>
    </label>
  );

  return (
    <>
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Notificaciones</h1>
          <p className="sm-dash__h-sub">Elige qué avisos quieres recibir {saving?'· guardando…':msg?'· '+msg:''}</p>
        </div>
      </div>
      <div className="sm-table-card" style={{padding:22}}>
        <Row k="email_tx" title="Correo · Confirmaciones de recarga" desc="Recibe un correo cada vez que una recarga se entregue." />
        <Row k="email_promos" title="Correo · Promociones" desc="Ofertas, descuentos y novedades del servicio." />
        <Row k="sms_tx" title="SMS · Recargas" desc="Confirmación instantánea por SMS (aplican tarifas)." />
        <Row k="push_tx" title="Push en el navegador" desc="Alertas instantáneas cuando tu recarga sea entregada." />
      </div>
    </>
  );
}

// ---------- Section: Ayuda ----------
function SectionAyuda() {
  const faqs = [
    ['¿En cuánto tiempo llega la recarga?', 'Normalmente en menos de 60 segundos. Si el operador tiene congestión puede tardar unos minutos.'],
    ['¿Qué operadores soportan?', 'Cubacel (móvil) y Nauta/Nauta Plus (internet).'],
    ['¿Puedo cancelar una recarga?', 'Una vez enviada al operador no es posible cancelarla. Si falla, se reembolsa automáticamente.'],
    ['¿Mis datos de pago están seguros?', 'Sí. Usamos cifrado SSL y solo guardamos los últimos 4 dígitos de la tarjeta. El número completo y el CVC nunca se almacenan.'],
    ['¿Puedo guardar contactos?', 'Sí, desde la sección "Contactos" puedes guardar destinatarios frecuentes.'],
  ];
  return (
    <>
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Centro de <em>ayuda</em></h1>
          <p className="sm-dash__h-sub">Respuestas rápidas a las dudas más comunes.</p>
        </div>
      </div>
      <div className="sm-table-card" style={{padding:'6px 22px'}}>
        {faqs.map(([q,a],i)=>(
          <details key={i} style={{padding:'16px 0', borderBottom: i<faqs.length-1?'1px solid #eee':'none'}}>
            <summary style={{cursor:'pointer', fontWeight:600, fontSize:15}}>{q}</summary>
            <p style={{marginTop:10, fontSize:14, color:'var(--ink-700)', lineHeight:1.6}}>{a}</p>
          </details>
        ))}
      </div>
      <div className="sm-table-card" style={{padding:22, marginTop:20, display:'flex', gap:12, flexWrap:'wrap'}}>
        <a className="sm-btn sm-btn--primary" href="mailto:support@smcuba.com"><Icon.Mail/> Escribir a soporte</a>
        <a className="sm-btn sm-btn--ghost" href="https://wa.me/10000000000?text=Hola%20SMCUBA%20necesito%20ayuda" target="_blank" rel="noopener"><Icon.WA/> WhatsApp</a>
      </div>
    </>
  );
}

// ---------- Section: Reseñas ----------
function SectionResenas() {
  const [myReviews, setMyReviews] = useStateCk([]);
  const [rating, setRating]       = useStateCk(5);
  const [text, setText]           = useStateCk('');
  const [err, setErr]             = useStateCk('');
  const [msg, setMsg]             = useStateCk('');
  const [saving, setSaving]       = useStateCk(false);

  const load = async () => {
    const { data } = await window.supabaseClient.from('reviews')
      .select('*').order('created_at', { ascending: false });
    setMyReviews(data || []);
  };

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

  const submit = async (e) => {
    e.preventDefault();
    setErr(''); setMsg('');
    if (text.trim().length < 10) { setErr('La reseña debe tener al menos 10 caracteres.'); return; }
    setSaving(true);
    const session = await window.SMAuth.session();
    const { error } = await window.supabaseClient.from('reviews').insert({
      user_id: session.user.id,
      rating,
      text: text.trim(),
    });
    setSaving(false);
    if (error) { setErr(error.message); return; }
    setMsg('¡Gracias! Tu reseña está pendiente de aprobación.');
    setText(''); setRating(5);
    load();
  };

  const RATING_LABELS = ['','Muy malo','Malo','Regular','Bueno','Excelente'];
  const statusBadge = (s) => ({
    approved: { label:'✔ Publicada',   bg:'#dcfce7', color:'#16a34a' },
    rejected: { label:'✕ Rechazada',   bg:'#fef2f2', color:'#dc2626' },
    pending:  { label:'◌ Pendiente',   bg:'#fffbeb', color:'#92400e' },
  }[s] || { label: s, bg:'#f1f5f9', color:'#64748b' });

  return (
    <>
      <div className="sm-dash__heading">
        <div>
          <h1 className="sm-dash__h-title">Mis <em>reseñas</em></h1>
          <p className="sm-dash__h-sub">Comparte tu experiencia. Las aprobadas aparecen en la página principal.</p>
        </div>
      </div>

      <form onSubmit={submit} className="sm-table-card" style={{padding:22, marginBottom:20}}>
        <h3 style={{margin:'0 0 14px', fontSize:17}}>Escribir una reseña</h3>

        {/* Star picker */}
        <div style={{display:'flex', alignItems:'center', gap:2, marginBottom:14}}>
          {[1,2,3,4,5].map(n => (
            <button key={n} type="button" onClick={() => setRating(n)} style={{
              fontSize:32, lineHeight:1, background:'none', border:'none', cursor:'pointer',
              color: n <= rating ? '#f59e0b' : '#d1d5db',
              transition:'color .15s', padding:'0 3px',
            }}>★</button>
          ))}
          <span style={{fontSize:13, color:'var(--ink-500)', marginLeft:8}}>
            {RATING_LABELS[rating]}
          </span>
        </div>

        <textarea
          required
          placeholder="Cuéntanos tu experiencia con SMCUBA (mínimo 10 caracteres)…"
          value={text}
          onChange={e => setText(e.target.value)}
          style={{
            width:'100%', boxSizing:'border-box', minHeight:110,
            padding:'12px 14px', borderRadius:12,
            border:'1.5px solid var(--cream-200)', fontSize:14,
            fontFamily:'inherit', resize:'vertical', outline:'none', transition:'border-color .2s',
          }}
          onFocus={e => e.target.style.borderColor = 'var(--brand-600)'}
          onBlur={e  => e.target.style.borderColor = 'var(--cream-200)'}
        />

        {err && <div style={{color:'#c62828', background:'#ffebee', padding:'8px 12px', borderRadius:8, fontSize:13, marginTop:8}}>{err}</div>}
        {msg && <div style={{color:'#2e7d32', background:'#e8f5e9', padding:'8px 12px', borderRadius:8, fontSize:13, marginTop:8}}>{msg}</div>}

        <button className="sm-btn sm-btn--primary" style={{marginTop:12}} disabled={saving}>
          {saving ? 'Enviando…' : <><Icon.Send/> Enviar reseña</>}
        </button>
      </form>

      <div className="sm-table-card">
        <div className="sm-table-card__head">
          <h3 className="sm-table-card__title">Mis reseñas ({myReviews.length})</h3>
        </div>
        {myReviews.length === 0
          ? <div style={{padding:28, textAlign:'center', color:'var(--ink-500)'}}>Aún no has enviado ninguna reseña.</div>
          : myReviews.map(r => {
            const badge = statusBadge(r.status);
            return (
              <div key={r.id} style={{display:'flex', gap:14, padding:'16px 20px', borderBottom:'1px solid #f1f5f9', alignItems:'flex-start'}}>
                <div style={{fontSize:20, color:'#f59e0b', flexShrink:0, letterSpacing:2, lineHeight:1.3}}>
                  {'★'.repeat(r.rating)}{'☆'.repeat(5-r.rating)}
                </div>
                <div style={{flex:1, minWidth:0}}>
                  <div style={{fontSize:14, color:'var(--ink-800)', lineHeight:1.5, marginBottom:4, wordBreak:'break-word'}}>{r.text}</div>
                  <div style={{fontSize:12, color:'var(--ink-400)'}}>{fmtDate(r.created_at)}</div>
                </div>
                <div style={{
                  fontSize:11, fontWeight:700, padding:'4px 10px', borderRadius:99,
                  background: badge.bg, color: badge.color, flexShrink:0, whiteSpace:'nowrap',
                }}>
                  {badge.label}
                </div>
              </div>
            );
          })
        }
      </div>
    </>
  );
}

// ---------- Dashboard shell ----------
function DashboardPage() {
  // Si hay una recarga pendiente en localStorage, arranca directamente en 'nueva'
  // sin depender del hash de la URL (que Supabase sobreescribe con el token OAuth).
  const [section, setSection] = useStateCk(() => {
    try { if (localStorage.getItem('sm_recarga')) return 'nueva'; } catch(_) {}
    return (location.hash||'#resumen').replace('#','');
  });
  const [user, setUser] = useStateCk(null);
  const [profile, setProfile] = useStateCk({});
  const [txs, setTxs] = useStateCk([]);
  const [contacts, setContacts] = useStateCk([]);
  const [methods, setMethods] = useStateCk([]);
  const [prefs, setPrefs] = useStateCk({ email_tx:true, email_promos:true, sms_tx:false, push_tx:true });

  // Ref always holds the latest txs so the polling interval sees fresh data
  const txsRef = useRefCk([]);
  useEffectRef(() => { txsRef.current = txs; }, [txs]);

  const go = (s) => { setSection(s); location.hash = '#'+s; };

  const loadAll = async () => {
    const u = await window.SMAuth.user();
    setUser(u);
    if (!u) return;
    const [p, t, c, m, np] = await Promise.all([
      window.supabaseClient.from('profiles').select('*').eq('id', u.id).maybeSingle(),
      window.supabaseClient.from('transactions').select('*').order('created_at',{ascending:false}),
      window.supabaseClient.from('contacts').select('*').order('favorite',{ascending:false}).order('name'),
      window.supabaseClient.from('payment_methods').select('*').order('is_default',{ascending:false}),
      window.supabaseClient.from('notification_prefs').select('*').eq('user_id', u.id).maybeSingle(),
    ]);
    setProfile(p.data || {});
    setTxs(t.data || []);
    setContacts(c.data || []);
    setMethods(m.data || []);
    if (np.data) setPrefs(np.data);
  };

  useEffectDash(() => {
    // Intento inmediato: funciona cuando la sesión ya está en localStorage
    // (login normal con email/contraseña o recarga de página).
    loadAll();

    // Con Google OAuth (flujo PKCE) la sesión llega de forma ASÍNCRONA:
    // el navegador aterriza en dashboard.html?code=xxx y Supabase hace
    // un intercambio de código en background. onAuthStateChange captura
    // ese momento exacto y vuelve a cargar el usuario sin importar el timing.
    // Escuchamos SIGNED_IN (OAuth nuevo) e INITIAL_SESSION (sesión existente
    // que se restaura antes de que el primer loadAll() termine).
    const { data: { subscription } } = window.supabaseClient.auth.onAuthStateChange(
      (event, session) => {
        if (event === 'SIGNED_IN' || event === 'INITIAL_SESSION') {
          if (session?.user) loadAll();
        }
      }
    );
    return () => subscription.unsubscribe();
  }, []);

  // Handle callback from external recharge processor (e.g. ?ref=SMC-XXXXX&status=ok)
  useEffectDash(() => {
    const params = new URLSearchParams(window.location.search);
    const callbackRef    = params.get('ref');
    const callbackStatus = params.get('status');
    if (!callbackRef || !callbackStatus) return;

    // Clean URL before any async work
    const cleanUrl = window.location.pathname + '#historial';
    window.history.replaceState({}, '', cleanUrl);
    setSection('historial');

    (async () => {
      const u = await window.SMAuth.user();
      if (!u) return;
      const finalStatus = callbackStatus === 'ok' ? 'ok' : 'failed';
      await window.supabaseClient
        .from('transactions')
        .update({ status: finalStatus })
        .eq('ref', callbackRef)
        .eq('user_id', u.id); // Security: only update own transactions
      loadAll();
    })();
  }, []);

  useEffectDash(() => {
    const h = () => setSection((location.hash||'#resumen').replace('#',''));
    window.addEventListener('hashchange', h); return () => window.removeEventListener('hashchange', h);
  }, []);

  // ── Poll operator Supabase every 15 s to detect completada/fallida ──
  // When the operator marks an order done, update the smcuba transaction status.
  useEffectDash(() => {
    const opUrl = window.SM_OPERATOR_SUPABASE_URL;
    const opKey = window.SM_OPERATOR_ANON_KEY;
    if (!opUrl || !opKey) return;

    const poll = async () => {
      const pending = (txsRef.current || []).filter(t => t.status === 'pending' && t.ref);
      if (!pending.length) return;

      if (!_opSb) _opSb = window.supabase.createClient(opUrl, opKey);
      const refs = pending.map(t => t.ref);

      const { data, error } = await _opSb.rpc('get_order_statuses', { refs });
      if (error || !data?.length) return;

      const u = await window.SMAuth.user();
      for (const order of data) {
        if (order.status !== 'completada' && order.status !== 'fallida') continue;
        const finalStatus = order.status === 'completada' ? 'ok' : 'failed';

        // Update local UI immediately
        setTxs(prev => prev.map(t =>
          t.ref === order.ref
            ? { ...t, status: finalStatus, rejection_reason: order.rejection_reason || null }
            : t
        ));

        // Persist to smcuba DB
        if (u) {
          // Try with rejection_reason; if column missing, update status only
          const upd = { status: finalStatus };
          if (order.rejection_reason) upd.rejection_reason = order.rejection_reason;
          const { error: e } = await window.supabaseClient
            .from('transactions').update(upd)
            .eq('ref', order.ref).eq('user_id', u.id);
          if (e && order.rejection_reason) {
            // Column may not exist yet — retry without it
            await window.supabaseClient
              .from('transactions').update({ status: finalStatus })
              .eq('ref', order.ref).eq('user_id', u.id);
          }
        }
      }
    };

    poll(); // immediate check on mount
    const id = setInterval(poll, 15000); // then every 15 s
    return () => clearInterval(id);
  }, []); // run once on mount — uses txsRef for fresh data

  const onLogout = async () => { await window.SMAuth.logout(); window.location.href='login.html'; };

  const { t: tDash } = useLang();

  const NavItem = ({ id, icon, children, danger }) => (
    <div className={`sm-dash__nav-item ${section===id?'sm-dash__nav-item--active':''}`} onClick={()=>go(id)} style={{cursor:'pointer', ...(danger?{color:'#c62828'}:{})}}>
      {icon} {children}
    </div>
  );

  return (
    <div className="page-host">
      <Nav />
      <div className="sm-dash">
        <aside className="sm-dash__side">
          <nav className="sm-dash__nav">
            <NavItem id="resumen" icon={<Icon.Target width="16" height="16"/>}>Resumen</NavItem>
            <NavItem id="nueva" icon={<Icon.Bolt/>}>{tDash('dash.nueva')}</NavItem>
            <NavItem id="historial" icon={<Icon.Clock/>}>{tDash('dash.historial')}</NavItem>
            <NavItem id="contactos" icon={<Icon.Heart width="16" height="16"/>}>{tDash('dash.contactos')}</NavItem>
            <div className="sm-dash__nav-section">Cuenta</div>
            <NavItem id="pagos" icon={<Icon.Lock/>}>{tDash('dash.pagos')}</NavItem>
            <NavItem id="seguridad" icon={<Icon.Shield/>}>{tDash('dash.seguridad')}</NavItem>
            <NavItem id="notificaciones" icon={<Icon.Mail/>}>{tDash('dash.notif')}</NavItem>
            <div className="sm-dash__nav-section">Soporte</div>
            <NavItem id="ayuda" icon={<Icon.Msg/>}>{tDash('dash.ayuda')}</NavItem>
            <NavItem id="resenas" icon={<Icon.Star width="16" height="16"/>}>{tDash('dash.resenas')}</NavItem>
            <a className="sm-dash__nav-item" href="https://wa.me/10000000000" target="_blank" rel="noopener" style={{textDecoration:'none', color:'inherit'}}><Icon.WA/> WhatsApp</a>
            <div className="sm-dash__nav-item" style={{cursor:'pointer', marginTop:12, color:'#c62828'}} onClick={onLogout}><Icon.Lock/> {tDash('dash.salir')}</div>
          </nav>
        </aside>
        <main className="sm-dash__main">
          {!user ? <div style={{padding:40, textAlign:'center', color:'#888'}}>Cargando…</div> :
            section==='nueva' ? <SectionNueva contacts={contacts} onCreated={loadAll} go={go}/> :
            section==='historial' ? <SectionHistorial txs={txs}/> :
            section==='contactos' ? <SectionContactos contacts={contacts} reload={loadAll}/> :
            section==='pagos' ? <SectionPagos methods={methods} reload={loadAll}/> :
            section==='seguridad' ? <SectionSeguridad user={user}/> :
            section==='notificaciones' ? <SectionNotificaciones prefs={prefs} setPrefs={setPrefs}/> :
            section==='ayuda'    ? <SectionAyuda/> :
            section==='resenas'  ? <SectionResenas/> :
            <SectionResumen user={{...user, ...profile}} txs={txs} go={go}/>
          }
        </main>
      </div>
    </div>
  );
}

Object.assign(window, { CheckoutPage, SuccessPage, DashboardPage, SubHero });
