// OxaPay checkout flow + Admin panel
function Checkout({ onNav }) {
  const [step, setStep] = React.useState(1);
  const [plan, setPlan] = React.useState('pro');
  const [billing, setBilling] = React.useState('monthly');
  const [crypto, setCrypto] = React.useState('USDT_TRC20');
  const [paid, setPaid] = React.useState(false);
  const [confirmations, setConfirmations] = React.useState(0);

  const selectedPlan = window.PLANS.find(p => p.id === plan);
  const amount = billing === 'yearly' ? Math.round(selectedPlan.price * 0.8 * 12) : selectedPlan.price;

  React.useEffect(() => {
    if (step === 3 && !paid) {
      const t1 = setTimeout(() => setConfirmations(1), 2500);
      const t2 = setTimeout(() => setConfirmations(2), 4500);
      const t3 = setTimeout(() => { setPaid(true); setStep(4); }, 6500);
      return () => { clearTimeout(t1); clearTimeout(t2); clearTimeout(t3); };
    }
  }, [step, paid]);

  return (
    <div style={{ minHeight: '100vh', background: 'var(--bg-0)', display: 'flex', flexDirection: 'column' }}>
      <nav style={{ padding: '18px 48px', display: 'flex', justifyContent: 'space-between', borderBottom: '1px solid var(--line-soft)' }}>
        <button onClick={() => onNav('landing')}><Logo67 size={24}/></button>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, fontSize: 13, color: 'var(--fg-2)' }}>
          <Icon name="shield" size={14} color="var(--accent)"/> Secure checkout via OxaPay
        </div>
      </nav>

      <div style={{ flex: 1, padding: '40px', display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 40, maxWidth: 1100, margin: '0 auto', width: '100%' }}>
        <div>
          <Stepper step={step}/>
          {step === 1 && <StepPlan plan={plan} setPlan={setPlan} billing={billing} setBilling={setBilling} onNext={() => setStep(2)}/>}
          {step === 2 && <StepPayment crypto={crypto} setCrypto={setCrypto} onBack={() => setStep(1)} onNext={() => setStep(3)}/>}
          {step === 3 && <StepConfirm crypto={crypto} amount={amount} confirmations={confirmations}/>}
          {step === 4 && <StepSuccess onNav={onNav}/>}
        </div>
        <OrderSummary plan={selectedPlan} billing={billing} amount={amount}/>
      </div>
    </div>
  );
}

function Stepper({ step }) {
  const steps = ['Plan', 'Payment method', 'Confirm', 'Done'];
  return (
    <div style={{ display: 'flex', gap: 6, marginBottom: 40 }}>
      {steps.map((s, i) => {
        const n = i + 1;
        const active = n === step, done = n < step;
        return (
          <div key={s} style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 8 }}>
            <div style={{ height: 3, borderRadius: 2, background: done || active ? 'var(--accent)' : 'var(--bg-2)' }}/>
            <div style={{ fontSize: 12, color: active ? 'var(--fg-0)' : 'var(--fg-3)', fontWeight: active ? 500 : 400 }}>
              {n}. {s}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function StepPlan({ plan, setPlan, billing, setBilling, onNext }) {
  return (
    <div>
      <h2 style={{ fontSize: 26, fontWeight: 500, letterSpacing: '-0.02em', margin: '0 0 8px' }}>Choose your plan</h2>
      <div style={{ fontSize: 13, color: 'var(--fg-2)', marginBottom: 24 }}>Bandwidth rolls over. Cancel anytime.</div>
      <div style={{ display: 'inline-flex', background: 'var(--bg-1)', border: '1px solid var(--line)', borderRadius: 999, padding: 3, marginBottom: 20 }}>
        {['monthly', 'yearly'].map(b => (
          <button key={b} onClick={() => setBilling(b)} style={{
            padding: '6px 14px', borderRadius: 999, fontSize: 12,
            background: billing === b ? 'var(--bg-2)' : 'transparent',
            color: billing === b ? 'var(--fg-0)' : 'var(--fg-2)',
          }}>{b === 'monthly' ? 'Monthly' : 'Yearly (-20%)'}</button>
        ))}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {window.PLANS.map(p => (
          <button key={p.id} onClick={() => setPlan(p.id)} style={{
            padding: 20, borderRadius: 12, textAlign: 'left',
            border: '1px solid', borderColor: plan === p.id ? 'var(--accent)' : 'var(--line)',
            background: plan === p.id ? 'rgba(61,220,196,0.05)' : 'var(--bg-1)',
            display: 'flex', alignItems: 'center', gap: 16,
          }}>
            <div style={{
              width: 20, height: 20, borderRadius: '50%',
              border: '2px solid', borderColor: plan === p.id ? 'var(--accent)' : 'var(--fg-3)',
              display: 'grid', placeItems: 'center',
            }}>
              {plan === p.id && <div style={{ width: 10, height: 10, borderRadius: '50%', background: 'var(--accent)' }}/>}
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 15, fontWeight: 500 }}>{p.name}</div>
              <div style={{ fontSize: 12, color: 'var(--fg-2)' }}>{p.gb} GB · {p.label}</div>
            </div>
            <div className="mono" style={{ fontSize: 20, fontWeight: 500 }}>
              ${billing === 'yearly' ? Math.round(p.price * 0.8) : p.price}
              <span style={{ fontSize: 12, color: 'var(--fg-3)' }}>/mo</span>
            </div>
          </button>
        ))}
      </div>
      <button className="btn btn-primary" style={{ marginTop: 24 }} onClick={onNext}>Continue to payment <Icon name="arrow_right" size={14}/></button>
    </div>
  );
}

const CRYPTOS = [
  { id: 'USDT_TRC20', name: 'USDT', network: 'TRC20', sym: '₮', color: '#26A17B', addr: 'TQrZ9wBsVs83pzRcBnVYhLkKkxYmVdWxmQ' },
  { id: 'USDT_ERC20', name: 'USDT', network: 'ERC20', sym: '₮', color: '#26A17B', addr: '0x9a8f...4b21' },
  { id: 'BTC', name: 'Bitcoin', network: 'Native', sym: '₿', color: '#f7931a', addr: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh' },
  { id: 'ETH', name: 'Ethereum', network: 'Native', sym: 'Ξ', color: '#627eea', addr: '0x9a8f3e2c7b4d1a5f6e2c3b4d1a5f6e2c3b4d1a5f' },
  { id: 'LTC', name: 'Litecoin', network: 'Native', sym: 'Ł', color: '#345d9d', addr: 'ltc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh' },
  { id: 'TRX', name: 'TRON', network: 'Native', sym: 'T', color: '#ff060a', addr: 'TQrZ9wBsVs83pzRcBnVYhLkKkxYmVdWxmQ' },
  { id: 'BNB', name: 'BNB', network: 'BEP20', sym: 'B', color: '#f3ba2f', addr: 'bnb1xy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh' },
  { id: 'DOGE', name: 'Dogecoin', network: 'Native', sym: 'Ð', color: '#c2a633', addr: 'DH5yaieqoZN36fDVciNyRueRGvGLR3mr7L' },
];

function StepPayment({ crypto, setCrypto, onBack, onNext }) {
  return (
    <div>
      <h2 style={{ fontSize: 26, fontWeight: 500, letterSpacing: '-0.02em', margin: '0 0 8px' }}>Pay with crypto</h2>
      <div style={{ fontSize: 13, color: 'var(--fg-2)', marginBottom: 24, display: 'flex', alignItems: 'center', gap: 8 }}>
        Powered by <OxaPayMark/> — on-chain settlement, no KYC.
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8 }}>
        {CRYPTOS.map(c => (
          <button key={c.id} onClick={() => setCrypto(c.id)} style={{
            padding: 14, borderRadius: 10, display: 'flex', alignItems: 'center', gap: 12, textAlign: 'left',
            border: '1px solid', borderColor: crypto === c.id ? 'var(--accent)' : 'var(--line)',
            background: crypto === c.id ? 'rgba(61,220,196,0.05)' : 'var(--bg-1)',
          }}>
            <div style={{ width: 32, height: 32, borderRadius: '50%', background: c.color, display: 'grid', placeItems: 'center', color: '#fff', fontWeight: 600 }}>{c.sym}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>{c.name}</div>
              <div className="mono" style={{ fontSize: 11, color: 'var(--fg-3)' }}>{c.network}</div>
            </div>
            {crypto === c.id && <Icon name="check" size={14} color="var(--accent)"/>}
          </button>
        ))}
      </div>
      <div style={{ display: 'flex', gap: 10, marginTop: 24 }}>
        <button className="btn btn-ghost" onClick={onBack}>Back</button>
        <button className="btn btn-primary" onClick={onNext} style={{ flex: 1, justifyContent: 'center' }}>
          Generate invoice <Icon name="arrow_right" size={14}/>
        </button>
      </div>
    </div>
  );
}

function OxaPayMark() {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '3px 8px', background: 'var(--bg-1)', border: '1px solid var(--line)', borderRadius: 6 }}>
      <span style={{ width: 14, height: 14, borderRadius: 3, background: 'linear-gradient(135deg, #4b8bf5, #3ddcc4)', display: 'grid', placeItems: 'center', fontSize: 9, fontWeight: 700, color: '#fff' }}>O</span>
      <span style={{ fontSize: 12, fontWeight: 500 }}>OxaPay</span>
    </span>
  );
}

function StepConfirm({ crypto, amount, confirmations }) {
  const c = CRYPTOS.find(x => x.id === crypto);
  const cryptoAmount = (amount / (crypto.startsWith('USDT') ? 1 : crypto === 'BTC' ? 65000 : crypto === 'ETH' ? 3200 : 1.2)).toFixed(crypto === 'BTC' ? 6 : 2);
  return (
    <div>
      <h2 style={{ fontSize: 26, fontWeight: 500, letterSpacing: '-0.02em', margin: '0 0 8px' }}>Send payment</h2>
      <div style={{ fontSize: 13, color: 'var(--fg-2)', marginBottom: 24 }}>
        Send exactly this amount to the address below. Invoice expires in <span className="mono" style={{ color: 'var(--warn)' }}>14:23</span>.
      </div>
      <div className="card" style={{ padding: 24, display: 'flex', gap: 24, alignItems: 'center', marginBottom: 16 }}>
        <div style={{ width: 140, height: 140, background: '#fff', padding: 10, borderRadius: 10, flexShrink: 0 }}>
          <QRPlaceholder/>
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', marginBottom: 6 }}>Amount</div>
          <div className="mono" style={{ fontSize: 22, fontWeight: 500, marginBottom: 14 }}>
            {cryptoAmount} <span style={{ color: c.color }}>{c.name}</span>
          </div>
          <div style={{ fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', marginBottom: 6 }}>Address ({c.network})</div>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <div className="mono" style={{ fontSize: 12, background: 'var(--bg-2)', padding: '8px 10px', borderRadius: 6, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.addr}</div>
            <button className="btn btn-ghost btn-sm"><Icon name="copy" size={12}/></button>
          </div>
        </div>
      </div>
      <div className="card" style={{ padding: 20 }}>
        <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 16, display: 'flex', alignItems: 'center', gap: 8 }}>
          <span className="dot" style={{ background: 'var(--accent)', animation: 'pulse 1.5s infinite' }}/>
          Waiting for confirmations ({confirmations}/2)
        </div>
        {[0, 1].map(i => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 0', fontSize: 13 }}>
            {confirmations > i
              ? <Icon name="check" size={14} color="var(--ok)"/>
              : <div style={{ width: 14, height: 14, border: '2px solid var(--fg-3)', borderTopColor: 'var(--accent)', borderRadius: '50%', animation: 'spin 0.8s linear infinite' }}/>
            }
            <span style={{ color: confirmations > i ? 'var(--fg-1)' : 'var(--fg-3)' }}>
              {i === 0 ? 'Block confirmation 1' : 'Block confirmation 2 (final)'}
            </span>
          </div>
        ))}
      </div>
      <style>{`@keyframes spin { to { transform: rotate(360deg); } } @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.3} }`}</style>
    </div>
  );
}

function QRPlaceholder() {
  const cells = Array.from({ length: 21 * 21 });
  return (
    <svg viewBox="0 0 21 21" style={{ width: '100%', height: '100%' }}>
      {cells.map((_, i) => {
        const x = i % 21, y = Math.floor(i / 21);
        // Finder patterns
        const inFinder = (x < 7 && y < 7) || (x > 13 && y < 7) || (x < 7 && y > 13);
        if (inFinder) {
          const fx = x < 7 ? x : x - 14, fy = y < 7 ? y : y - 14;
          const onEdge = fx === 0 || fx === 6 || fy === 0 || fy === 6;
          const inCenter = fx >= 2 && fx <= 4 && fy >= 2 && fy <= 4;
          if (onEdge || inCenter) return <rect key={i} x={x} y={y} width="1" height="1" fill="#000"/>;
          return null;
        }
        // Pseudo-random
        const h = (x * 7 + y * 13 + x * y) % 7;
        if (h < 3) return <rect key={i} x={x} y={y} width="1" height="1" fill="#000"/>;
        return null;
      })}
    </svg>
  );
}

function StepSuccess({ onNav }) {
  return (
    <div style={{ textAlign: 'center', padding: '40px 0' }}>
      <div style={{
        width: 72, height: 72, borderRadius: '50%',
        background: 'rgba(74,222,128,0.1)', border: '2px solid var(--ok)',
        margin: '0 auto 24px', display: 'grid', placeItems: 'center',
      }}>
        <Icon name="check" size={32} color="var(--ok)"/>
      </div>
      <h2 style={{ fontSize: 28, fontWeight: 500, letterSpacing: '-0.02em', margin: '0 0 8px' }}>Payment received</h2>
      <div style={{ fontSize: 14, color: 'var(--fg-2)', marginBottom: 24 }}>
        Your plan is active. Bandwidth is ready to use right now.
      </div>
      <div className="card" style={{ padding: 20, textAlign: 'left', marginBottom: 24 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, padding: '6px 0' }}>
          <span style={{ color: 'var(--fg-2)' }}>Transaction</span>
          <span className="mono" style={{ color: 'var(--accent)' }}>0x9a8f3e...4b21f2</span>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, padding: '6px 0' }}>
          <span style={{ color: 'var(--fg-2)' }}>Invoice</span>
          <span className="mono">INV-2026-04-21</span>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, padding: '6px 0' }}>
          <span style={{ color: 'var(--fg-2)' }}>Status</span>
          <span className="chip chip-ok">Confirmed</span>
        </div>
      </div>
      <button className="btn btn-primary" onClick={() => onNav('dashboard')} style={{ width: '100%', justifyContent: 'center' }}>
        Go to dashboard <Icon name="arrow_right" size={14}/>
      </button>
    </div>
  );
}

function OrderSummary({ plan, billing, amount }) {
  return (
    <div style={{ position: 'sticky', top: 40, alignSelf: 'start' }}>
      <div className="card" style={{ padding: 24 }}>
        <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 20, color: 'var(--fg-2)' }}>Order summary</div>
        <div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: 14, borderBottom: '1px solid var(--line-soft)' }}>
          <div>
            <div style={{ fontSize: 14, fontWeight: 500 }}>{plan.name} plan</div>
            <div style={{ fontSize: 12, color: 'var(--fg-3)' }}>{plan.gb} GB · {billing}</div>
          </div>
          <div className="mono" style={{ fontSize: 14 }}>${amount.toFixed(2)}</div>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', padding: '12px 0', fontSize: 12, color: 'var(--fg-2)' }}>
          <span>Subtotal</span><span className="mono">${amount.toFixed(2)}</span>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', padding: '0 0 12px', fontSize: 12, color: 'var(--fg-2)' }}>
          <span>Network fee</span><span className="mono">$0.00</span>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', padding: '12px 0', borderTop: '1px solid var(--line-soft)', fontSize: 15, fontWeight: 500 }}>
          <span>Total</span><span className="mono">${amount.toFixed(2)}</span>
        </div>
        <div style={{ marginTop: 20, padding: 12, background: 'var(--bg-2)', borderRadius: 8, fontSize: 11, color: 'var(--fg-2)', lineHeight: 1.5 }}>
          <Icon name="shield" size={12} color="var(--accent)" style={{ verticalAlign: 'middle' }}/> {' '}
          100% refund within 72h. No questions asked.
        </div>
      </div>
    </div>
  );
}

// ========== ADMIN PANEL ==========
function Admin({ onNav }) {
  const [section, setSection] = React.useState('ops');
  const [mustChange, setMustChange] = React.useState(() => !!(window.__user && window.__user.must_change_pw));

  // If the admin still has the default password, block everything behind a
  // forced change modal. Once they change it, we clear the flag locally.
  if (mustChange) {
    return (
      <div style={{ minHeight: '100vh', background: 'var(--bg-0)', display: 'grid', placeItems: 'center', padding: 20 }}>
        <ForceChangePasswordModal
          onSuccess={() => {
            if (window.__user) window.__user.must_change_pw = false;
            setMustChange(false);
          }}
          onLogout={() => {
            try { window.__logout && window.__logout(); } catch (_) {}
          }}
        />
      </div>
    );
  }

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '240px 1fr', minHeight: '100vh', background: 'var(--bg-0)' }}>
      <Sidebar section={section} setSection={setSection} onNav={onNav} mode="admin"/>
      <div>
        <TopBar mode="admin" onNav={onNav}/>
        <main style={{ padding: 32 }}>
          {section === 'ops' && <AdminOps/>}
          {section === 'users' && <AdminUsers/>}
          {section === 'plans' && <AdminPlans/>}
          {section === 'revenue' && <AdminRevenue/>}
          {section === 'oxapay' && <AdminOxapay/>}
          {section === 'tickets' && <AdminTickets/>}
          {section === 'coupons' && <AdminCoupons/>}
          {section === 'logs' && <AdminLogs/>}
        </main>
      </div>
    </div>
  );
}

// Standalone forced-change panel shown before anything else when the default
// admin password hasn't been changed yet. Self-contained (not a Modal) because
// the rest of the admin shell is intentionally not rendered.
function ForceChangePasswordModal({ onSuccess, onLogout }) {
  const [current, setCurrent] = React.useState('');
  const [next, setNext]       = React.useState('');
  const [confirm, setConfirm] = React.useState('');
  const [err, setErr]         = React.useState(null);
  const [busy, setBusy]       = React.useState(false);

  const submit = async (e) => {
    e.preventDefault();
    setErr(null);
    if (next.length < 10) { setErr('New password must be at least 10 characters.'); return; }
    if (next !== confirm) { setErr('Passwords do not match.'); return; }
    if (next === current) { setErr('New password must be different from the current one.'); return; }
    setBusy(true);
    try {
      await window.api('/api/auth/change-password', {
        method: 'POST',
        body: { current_password: current, new_password: next },
      });
      onSuccess();
    } catch (e) {
      setErr(window.apiErrorMessage(e));
      setBusy(false);
    }
  };

  return (
    <div className="card" style={{ maxWidth: 440, width: '100%', padding: 32 }}>
      <div style={{
        width: 44, height: 44, borderRadius: '50%',
        background: 'color-mix(in oklab, var(--warn) 18%, transparent)',
        display: 'grid', placeItems: 'center', marginBottom: 14,
      }}>
        <Icon name="alert" size={20} color="var(--warn)"/>
      </div>
      <div style={{ fontSize: 20, fontWeight: 500, letterSpacing: '-0.02em', marginBottom: 6 }}>
        Change default admin password
      </div>
      <div style={{ fontSize: 13, color: 'var(--fg-2)', marginBottom: 22, lineHeight: 1.5 }}>
        You're signed in with the default admin credentials. Set a new password before you can access any admin functions.
      </div>

      <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div>
          <label style={{ fontSize: 11, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.08em', display: 'block', marginBottom: 6 }}>Current password</label>
          <input type="password" value={current} onChange={e => setCurrent(e.target.value)} required style={{ width: '100%' }} autoFocus/>
        </div>
        <div>
          <label style={{ fontSize: 11, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.08em', display: 'block', marginBottom: 6 }}>New password (min 10 chars)</label>
          <input type="password" value={next} onChange={e => setNext(e.target.value)} required minLength={10} style={{ width: '100%' }}/>
        </div>
        <div>
          <label style={{ fontSize: 11, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.08em', display: 'block', marginBottom: 6 }}>Confirm new password</label>
          <input type="password" value={confirm} onChange={e => setConfirm(e.target.value)} required style={{ width: '100%' }}/>
        </div>

        {err && <div role="alert" style={{ fontSize: 12, color: 'var(--err)' }}>{err}</div>}

        <div style={{ display: 'flex', gap: 8, justifyContent: 'space-between', marginTop: 8 }}>
          <button type="button" className="btn btn-ghost" onClick={onLogout} disabled={busy}>Sign out</button>
          <button type="submit" className="btn btn-primary" disabled={busy}>
            {busy ? 'Saving…' : 'Change password'}
          </button>
        </div>
      </form>
    </div>
  );
}

function AdminOps() {
  const [m, setM] = React.useState(null);
  const [err, setErr] = React.useState(null);

  React.useEffect(() => {
    window.api('/api/admin/metrics')
      .then(setM)
      .catch(e => setErr(window.apiErrorMessage(e)));
  }, []);

  if (err) {
    return (
      <div>
        <PageHeader title="Operations"/>
        <div role="alert" style={{
          fontSize: 13, color: 'var(--err)',
          background: 'color-mix(in oklab, var(--err) 10%, transparent)',
          border: '1px solid color-mix(in oklab, var(--err) 30%, transparent)',
          padding: '12px 16px', borderRadius: 8,
        }}>{err}</div>
      </div>
    );
  }
  if (!m) {
    return (
      <div>
        <PageHeader title="Operations"/>
        <div className="card" style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)' }}>
          <Spinner/> <span style={{ marginLeft: 8 }}>Loading metrics…</span>
        </div>
      </div>
    );
  }

  const fmt$ = (n) => `$${Number(n || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
  const fmtN = (n) => Number(n || 0).toLocaleString();

  const cards = [
    { k: 'Deposits (30d)',    v: fmt$(m.revenue.mrr_topups), sub: `${fmt$(m.revenue.today_topups)} today` },
    { k: 'Plan sales (30d)',  v: fmt$(m.revenue.mrr_spend),  sub: `${fmt$(m.revenue.today_spend)} today` },
    { k: 'Users',             v: fmtN(m.users),              sub: `${fmtN(m.paying_users)} paying · +${m.signups_24h} today` },
    { k: 'Open tickets',      v: fmtN(m.open_tickets),       sub: `${fmtN(m.pending_orders)} pending orders` },
  ];

  return (
    <div>
      <PageHeader title="Operations" subtitle="Real-time business overview"/>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginBottom: 24 }}>
        {cards.map(c => (
          <div key={c.k} className="card" style={{ padding: 20 }}>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 8 }}>{c.k}</div>
            <div className="mono" style={{ fontSize: 26, fontWeight: 500, letterSpacing: '-0.02em', marginBottom: 4 }}>{c.v}</div>
            <div style={{ fontSize: 11, color: 'var(--fg-3)' }}>{c.sub}</div>
          </div>
        ))}
      </div>

      {/* Revenue chart (simple inline) */}
      <div className="card" style={{ padding: 24, marginBottom: 24 }}>
        <div style={{ fontSize: 14, fontWeight: 500, marginBottom: 16 }}>Last 30 days · deposits vs plan sales</div>
        <RevenueMiniChart data={m.revenue_30d}/>
      </div>

      {/* Top plans */}
      <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
        <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--line)' }}>
          <div style={{ fontSize: 14, fontWeight: 500 }}>Top plans (30 days)</div>
        </div>
        {m.top_plans.length === 0 ? (
          <div style={{ padding: 32, textAlign: 'center', fontSize: 13, color: 'var(--fg-3)' }}>No purchases yet.</div>
        ) : (
          <table style={{ width: '100%' }}>
            <thead>
              <tr style={{ background: 'var(--bg-2)', borderBottom: '1px solid var(--line)' }}>
                {['Plan', 'Purchases', 'Revenue'].map(h => (
                  <th key={h} style={{ padding: '10px 20px', fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', fontWeight: 500, textAlign: 'left' }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {m.top_plans.map((p, i) => (
                <tr key={i} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                  <td style={{ padding: '12px 20px', fontSize: 13 }}>{p.plan_snippet || '—'}</td>
                  <td style={{ padding: '12px 20px' }} className="mono"><span style={{ fontSize: 13 }}>{p.purchases}</span></td>
                  <td style={{ padding: '12px 20px' }} className="mono"><span style={{ fontSize: 13, color: 'var(--ok)' }}>{fmt$(p.revenue)}</span></td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

function RevenueMiniChart({ data }) {
  if (!data || data.length === 0) {
    return <div style={{ fontSize: 13, color: 'var(--fg-3)', textAlign: 'center', padding: 32 }}>No data in the last 30 days.</div>;
  }
  const max = Math.max(...data.map(d => Math.max(d.topups, d.spend)), 1);
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: `repeat(${data.length}, 1fr)`, alignItems: 'end', gap: 2, height: 120 }}>
        {data.map((d, i) => {
          const topH  = Math.round((d.topups / max) * 100);
          const spendH = Math.round((d.spend / max) * 100);
          return (
            <div key={i} title={`${d.day}: $${d.topups.toFixed(2)} deposits, $${d.spend.toFixed(2)} spent`}
              style={{ display: 'flex', alignItems: 'flex-end', gap: 2, height: '100%' }}>
              <div style={{ flex: 1, height: `${topH}%`, background: 'var(--accent)', borderRadius: '2px 2px 0 0', minHeight: 1 }}/>
              <div style={{ flex: 1, height: `${spendH}%`, background: 'var(--warn)', borderRadius: '2px 2px 0 0', minHeight: 1 }}/>
            </div>
          );
        })}
      </div>
      <div style={{ display: 'flex', gap: 20, marginTop: 12, fontSize: 11, color: 'var(--fg-3)' }}>
        <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <span style={{ width: 10, height: 10, background: 'var(--accent)', borderRadius: 2 }}/>Deposits
        </span>
        <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <span style={{ width: 10, height: 10, background: 'var(--warn)', borderRadius: 2 }}/>Plan sales
        </span>
      </div>
    </div>
  );
}

function AdminUsers() {
  const [users, setUsers] = React.useState(null);
  const [total, setTotal] = React.useState(0);
  const [search, setSearch] = React.useState('');
  const [err, setErr] = React.useState(null);
  const [adjustUser, setAdjustUser] = React.useState(null);
  const [detailUserId, setDetailUserId] = React.useState(null);

  const load = React.useCallback(async () => {
    try {
      const qs = search.trim() ? `?q=${encodeURIComponent(search.trim())}` : '';
      const d = await window.api(`/api/admin/users${qs}`);
      setUsers(d.users || []);
      setTotal(d.total || 0);
    } catch (e) {
      setErr(window.apiErrorMessage(e));
      setUsers([]);
    }
  }, [search]);

  React.useEffect(() => {
    const t = setTimeout(load, 150);  // debounce search
    return () => clearTimeout(t);
  }, [load]);

  const fmtDate = (iso) => {
    if (!iso) return '—';
    const d = new Date(iso + (iso.endsWith('Z') ? '' : 'Z'));
    return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
  };

  return (
    <div>
      <PageHeader title="Users" subtitle={`${total} total user${total === 1 ? '' : 's'}`}/>

      {err && (
        <div role="alert" style={{
          fontSize: 12, color: 'var(--err)',
          background: 'color-mix(in oklab, var(--err) 10%, transparent)',
          border: '1px solid color-mix(in oklab, var(--err) 30%, transparent)',
          padding: '9px 12px', borderRadius: 8, marginBottom: 16,
          display: 'flex', alignItems: 'center', gap: 8,
        }}>
          <Icon name="alert" size={13}/> {err}
        </div>
      )}

      <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
        <div style={{ padding: 16, borderBottom: '1px solid var(--line)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 8, padding: '7px 12px' }}>
            <Icon name="search" size={14} color="var(--fg-3)"/>
            <input
              value={search}
              onChange={e => setSearch(e.target.value)}
              style={{ border: 'none', background: 'transparent', padding: 0, flex: 1, fontSize: 13 }}
              placeholder="Search by email…"
            />
          </div>
        </div>

        {users === null ? (
          <div style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)', fontSize: 13 }}>
            <Spinner/> <span style={{ marginLeft: 8 }}>Loading…</span>
          </div>
        ) : users.length === 0 ? (
          <div style={{ padding: 48, textAlign: 'center' }}>
            <div style={{ fontSize: 14, color: 'var(--fg-1)', marginBottom: 6 }}>
              {search ? 'No users match that search.' : 'No users yet.'}
            </div>
          </div>
        ) : (
          <table style={{ width: '100%' }}>
            <thead>
              <tr style={{ background: 'var(--bg-2)', borderBottom: '1px solid var(--line)' }}>
                {['User', 'Role', 'Plan', 'Usage', 'Balance', 'Joined', 'Status', ''].map(h => (
                  <th key={h} style={{ padding: '10px 16px', fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', fontWeight: 500, textAlign: 'left' }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {users.map(u => {
                const locked = u.locked_until && new Date(u.locked_until) > new Date();
                const unlimited = (u.gb_limit || 0) >= 9999;
                return (
                  <tr key={u.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                    <td style={{ padding: '14px 16px' }}>
                      <button
                        onClick={() => setDetailUserId(u.id)}
                        style={{ background: 'transparent', cursor: 'pointer', textAlign: 'left', padding: 0 }}
                        title="View details"
                      >
                        <div className="mono" style={{ fontSize: 12, color: 'var(--accent)' }}>{u.email}</div>
                        <div style={{ fontSize: 10, color: 'var(--fg-3)', marginTop: 2 }}>id #{u.id}</div>
                      </button>
                    </td>
                    <td style={{ padding: '14px 16px' }}>
                      <span className={u.role === 'admin' ? 'chip chip-accent' : 'chip'}>{u.role}</span>
                    </td>
                    <td style={{ padding: '14px 16px' }}>
                      <span className="chip">{u.plan === 'free' ? 'No plan' : u.plan}</span>
                    </td>
                    <td style={{ padding: '14px 16px' }} className="mono">
                      <span style={{ fontSize: 12 }}>
                        {unlimited ? `${Number(u.gb_used).toFixed(1)} / ∞ GB` : `${Number(u.gb_used).toFixed(1)} / ${Number(u.gb_limit).toFixed(0)} GB`}
                      </span>
                    </td>
                    <td style={{ padding: '14px 16px' }} className="mono">
                      <span style={{ fontSize: 13, color: u.balance_usd > 0 ? 'var(--ok)' : 'var(--fg-1)' }}>
                        ${Number(u.balance_usd || 0).toFixed(2)}
                      </span>
                    </td>
                    <td style={{ padding: '14px 16px', fontSize: 12, color: 'var(--fg-2)' }}>{fmtDate(u.created_at)}</td>
                    <td style={{ padding: '14px 16px' }}>
                      <span className={locked ? 'chip chip-err' : 'chip chip-ok'}>{locked ? 'locked' : 'active'}</span>
                    </td>
                    <td style={{ padding: '14px 16px' }}>
                      <button
                        className="btn btn-ghost btn-sm"
                        title="Adjust balance"
                        onClick={() => setAdjustUser(u)}
                      >
                        ±$
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>

      {adjustUser && (
        <AdjustBalanceModal
          user={adjustUser}
          onClose={() => setAdjustUser(null)}
          onSaved={() => { setAdjustUser(null); load(); }}
        />
      )}

      {detailUserId !== null && (
        <UserDetailModal
          userId={detailUserId}
          onClose={() => setDetailUserId(null)}
          onAdjustBalance={(u) => { setDetailUserId(null); setAdjustUser(u); }}
        />
      )}
    </div>
  );
}

function AdjustBalanceModal({ user, onClose, onSaved }) {
  const [mode, setMode] = React.useState('add');   // add | subtract
  const [amount, setAmount] = React.useState(10);
  const [note, setNote] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);

  const submit = async (e) => {
    e.preventDefault();
    const n = Number(amount);
    if (!Number.isFinite(n) || n <= 0) { setErr('Amount must be a positive number.'); return; }
    setBusy(true); setErr(null);
    try {
      const signed = mode === 'add' ? n : -n;
      await window.api(`/api/admin/users/${user.id}/balance`, {
        method: 'POST',
        body: { amount_usd: signed, note: note || null },
      });
      onSaved();
    } catch (e) {
      setErr(window.apiErrorMessage(e));
      setBusy(false);
    }
  };

  return (
    <Modal onClose={onClose} title={`Adjust balance · ${user.email}`}>
      <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div style={{ fontSize: 13, color: 'var(--fg-2)' }}>
          Current: <span className="mono" style={{ color: 'var(--fg-0)' }}>${Number(user.balance_usd || 0).toFixed(2)}</span>
        </div>

        <div>
          <label style={{ fontSize: 11, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.08em', display: 'block', marginBottom: 6 }}>Action</label>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
            {[
              { id: 'add',      l: '＋ Credit'  },
              { id: 'subtract', l: '− Debit' },
            ].map(b => (
              <button
                key={b.id}
                type="button"
                onClick={() => setMode(b.id)}
                style={{
                  padding: '10px', fontSize: 12, cursor: 'pointer',
                  border: '1px solid', borderColor: mode === b.id ? 'var(--accent)' : 'var(--line)',
                  borderRadius: 8,
                  background: mode === b.id ? 'color-mix(in oklab, var(--accent) 14%, transparent)' : 'var(--bg-2)',
                  color: mode === b.id ? 'var(--accent)' : 'var(--fg-1)',
                }}
              >{b.l}</button>
            ))}
          </div>
        </div>

        <div>
          <label style={{ fontSize: 11, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.08em', display: 'block', marginBottom: 6 }}>Amount (USD)</label>
          <input type="number" min="0.01" step="0.01" value={amount} onChange={e => setAmount(e.target.value)} style={{ width: '100%' }} autoFocus/>
        </div>

        <div>
          <label style={{ fontSize: 11, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.08em', display: 'block', marginBottom: 6 }}>Note (optional)</label>
          <input value={note} onChange={e => setNote(e.target.value)} placeholder="e.g. Refund for order #xyz" maxLength={200} style={{ width: '100%' }}/>
        </div>

        <div style={{ fontSize: 12, color: 'var(--fg-2)', background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 8, padding: '10px 12px' }}>
          New balance: <span className="mono" style={{ color: mode === 'add' ? 'var(--ok)' : 'var(--warn)' }}>
            ${(Number(user.balance_usd || 0) + (mode === 'add' ? 1 : -1) * Number(amount || 0)).toFixed(2)}
          </span>
        </div>

        {err && <div role="alert" style={{ fontSize: 12, color: 'var(--err)' }}>{err}</div>}

        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Cancel</button>
          <button type="submit" className="btn btn-primary" disabled={busy || !Number(amount)}>
            {busy ? <><Spinner/> Applying…</> : 'Apply'}
          </button>
        </div>
      </form>
    </Modal>
  );
}

function UserDetailModal({ userId, onClose, onAdjustBalance }) {
  const [data, setData] = React.useState(null);
  const [err, setErr]   = React.useState(null);
  const [tab, setTab]   = React.useState('overview');

  React.useEffect(() => {
    setData(null); setErr(null);
    window.api(`/api/admin/users/${userId}/detail`)
      .then(setData)
      .catch(e => setErr(window.apiErrorMessage(e)));
  }, [userId]);

  const fmtMoney = (n) => `$${Number(n || 0).toFixed(2)}`;
  const fmtDate = (iso) => {
    if (!iso) return '—';
    const d = new Date(iso + (iso.endsWith('Z') ? '' : 'Z'));
    return d.toLocaleString(undefined, { month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit' });
  };
  const fmtRelative = (iso) => {
    if (!iso) return 'never';
    const ms = Date.now() - new Date(iso + (iso.endsWith('Z') ? '' : 'Z')).getTime();
    const s = Math.floor(ms / 1000);
    if (s < 60)    return `${s}s ago`;
    if (s < 3600)  return `${Math.floor(s / 60)}m ago`;
    if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
    return `${Math.floor(s / 86400)}d ago`;
  };

  if (err) {
    return (
      <Modal onClose={onClose} title="User detail">
        <div role="alert" style={{ fontSize: 13, color: 'var(--err)' }}>{err}</div>
      </Modal>
    );
  }
  if (!data) {
    return (
      <Modal onClose={onClose} title="User detail">
        <div style={{ padding: 32, textAlign: 'center', color: 'var(--fg-3)' }}>
          <Spinner/> <span style={{ marginLeft: 8 }}>Loading…</span>
        </div>
      </Modal>
    );
  }

  const u = data.user;
  const t = data.totals;

  const tabs = [
    { id: 'overview', label: 'Overview' },
    { id: 'proxies',  label: `Proxies (${data.proxies.length})` },
    { id: 'topups',   label: `Topups (${t.topup_count})` },
    { id: 'plans',    label: `Plans bought (${t.purchase_count})` },
    { id: 'coupons',  label: `Coupons (${data.coupons_redeemed.length})` },
    { id: 'tickets',  label: `Tickets (${data.tickets.length})` },
  ];

  return (
    <Modal onClose={onClose} title={`User · ${u.email}`}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {/* HERO: account meta + key totals */}
        <div style={{ padding: 14, background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 10 }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 14, marginBottom: 12 }}>
            <div>
              <div style={{ fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Account</div>
              <div className="mono" style={{ fontSize: 13, color: 'var(--fg-1)' }}>{u.email}</div>
              <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 2 }}>
                id #{u.id} · {u.role} · joined {fmtDate(u.created_at)}
              </div>
            </div>
            <div>
              <div style={{ fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Last login</div>
              <div style={{ fontSize: 13, color: 'var(--fg-1)' }}>{fmtRelative(u.last_login_at)}</div>
              <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 2 }}>
                {u.last_login_at ? fmtDate(u.last_login_at) : 'no login recorded'}
              </div>
            </div>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10 }}>
            <Stat label="Balance"        value={fmtMoney(u.balance_usd)} color="var(--ok)"/>
            <Stat label="Total deposited" value={fmtMoney(t.lifetime_deposits)}/>
            <Stat label="Total spent"    value={fmtMoney(t.lifetime_spend)}/>
            <Stat label="Active proxies" value={String(t.proxy_count)}/>
          </div>
        </div>

        {/* Quick context strip */}
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', fontSize: 11 }}>
          {u.locked_until && new Date(u.locked_until) > new Date()
            ? <span className="chip chip-err">locked until {fmtDate(u.locked_until)}</span>
            : <span className="chip chip-ok">active</span>}
          <span className="chip">plan: {u.plan === 'free' ? 'no plan' : u.plan}</span>
          {u.referral_code && <span className="chip">ref code: <span className="mono" style={{ marginLeft: 4 }}>{u.referral_code}</span></span>}
          {data.referrer && <span className="chip chip-accent">referred by: {data.referrer.email}</span>}
          {t.referred_count > 0 && <span className="chip chip-accent">referred {t.referred_count} user{t.referred_count === 1 ? '' : 's'}</span>}
          {t.lifetime_referral_earnings > 0 && <span className="chip">earned {fmtMoney(t.lifetime_referral_earnings)} in referrals</span>}
          {u.signup_ip && <span className="chip">signup IP: <span className="mono" style={{ marginLeft: 4 }}>{u.signup_ip}</span></span>}
        </div>

        {/* Tab nav */}
        <div style={{ display: 'flex', gap: 4, borderBottom: '1px solid var(--line)' }}>
          {tabs.map(tt => (
            <button
              key={tt.id}
              onClick={() => setTab(tt.id)}
              style={{
                background: 'transparent', cursor: 'pointer',
                padding: '8px 12px', fontSize: 12,
                color: tab === tt.id ? 'var(--accent)' : 'var(--fg-2)',
                borderBottom: '2px solid', borderColor: tab === tt.id ? 'var(--accent)' : 'transparent',
                marginBottom: -1,
              }}
            >{tt.label}</button>
          ))}
        </div>

        {/* Tab content */}
        <div style={{ minHeight: 200 }}>
          {tab === 'overview' && (
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8, fontSize: 12 }}>
              <KV label="Bandwidth used"   value={`${Number(u.gb_used).toFixed(2)} GB`}/>
              <KV label="Bandwidth limit"  value={u.gb_limit >= 9999 ? '∞ (unmetered)' : `${Number(u.gb_limit).toFixed(0)} GB`}/>
              <KV label="First purchase"   value={u.first_purchase_at ? fmtDate(u.first_purchase_at) : 'none yet'}/>
              <KV label="Admin adjustments" value={t.lifetime_admin_adjust !== 0 ? fmtMoney(t.lifetime_admin_adjust) : 'none'}/>
            </div>
          )}

          {tab === 'proxies' && (data.proxies.length === 0
            ? <Empty msg="No proxies issued."/>
            : <Table headers={['Plan', 'Username', 'Host:Port', 'Issued']}>
                {data.proxies.map(p => (
                  <tr key={p.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                    <td style={{ padding: '8px 10px', fontSize: 12 }}>{p.label || p.plan_id || '—'}</td>
                    <td style={{ padding: '8px 10px', fontSize: 11 }} className="mono">{p.username}</td>
                    <td style={{ padding: '8px 10px', fontSize: 11 }} className="mono">{p.host}:{p.port}</td>
                    <td style={{ padding: '8px 10px', fontSize: 11, color: 'var(--fg-3)' }}>{fmtDate(p.created_at)}</td>
                  </tr>
                ))}
              </Table>
          )}

          {tab === 'topups' && (data.topups.length === 0
            ? <Empty msg="No deposits."/>
            : <Table headers={['Date', 'Amount', 'Note']}>
                {data.topups.map(r => (
                  <tr key={r.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                    <td style={{ padding: '8px 10px', fontSize: 11, color: 'var(--fg-3)' }}>{fmtDate(r.created_at)}</td>
                    <td style={{ padding: '8px 10px' }} className="mono"><span style={{ fontSize: 12, color: 'var(--ok)' }}>+{fmtMoney(r.amount_usd)}</span></td>
                    <td style={{ padding: '8px 10px', fontSize: 11, color: 'var(--fg-2)' }}>{r.note || '—'}</td>
                  </tr>
                ))}
              </Table>
          )}

          {tab === 'plans' && (data.purchases.length === 0
            ? <Empty msg="No plans purchased."/>
            : <Table headers={['Date', 'Amount', 'Plan']}>
                {data.purchases.map(r => (
                  <tr key={r.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                    <td style={{ padding: '8px 10px', fontSize: 11, color: 'var(--fg-3)' }}>{fmtDate(r.created_at)}</td>
                    <td style={{ padding: '8px 10px' }} className="mono"><span style={{ fontSize: 12 }}>{fmtMoney(-r.amount_usd)}</span></td>
                    <td style={{ padding: '8px 10px', fontSize: 11, color: 'var(--fg-2)' }}>{r.note || '—'}</td>
                  </tr>
                ))}
              </Table>
          )}

          {tab === 'coupons' && (data.coupons_redeemed.length === 0
            ? <Empty msg="No coupons redeemed."/>
            : <Table headers={['Date', 'Code', 'Plan', 'Saved']}>
                {data.coupons_redeemed.map(r => (
                  <tr key={r.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                    <td style={{ padding: '8px 10px', fontSize: 11, color: 'var(--fg-3)' }}>{fmtDate(r.created_at)}</td>
                    <td style={{ padding: '8px 10px', fontSize: 12 }} className="mono">{r.coupon_code}</td>
                    <td style={{ padding: '8px 10px' }}><span className="chip" style={{ fontSize: 10 }}>{r.plan_id}</span></td>
                    <td style={{ padding: '8px 10px' }} className="mono"><span style={{ fontSize: 12, color: 'var(--ok)' }}>−{fmtMoney(r.saved_usd)}</span></td>
                  </tr>
                ))}
              </Table>
          )}

          {tab === 'tickets' && (data.tickets.length === 0
            ? <Empty msg="No tickets opened."/>
            : <Table headers={['#', 'Subject', 'Status', 'Opened']}>
                {data.tickets.map(t => (
                  <tr key={t.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                    <td style={{ padding: '8px 10px', fontSize: 11 }} className="mono">#{t.id}</td>
                    <td style={{ padding: '8px 10px', fontSize: 12 }}>{t.subject}</td>
                    <td style={{ padding: '8px 10px' }}><span className={t.status === 'open' ? 'chip chip-warn' : t.status === 'closed' ? 'chip chip-ok' : 'chip'} style={{ fontSize: 10 }}>{t.status}</span></td>
                    <td style={{ padding: '8px 10px', fontSize: 11, color: 'var(--fg-3)' }}>{fmtDate(t.created_at)}</td>
                  </tr>
                ))}
              </Table>
          )}
        </div>

        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
          <button className="btn btn-ghost" onClick={onClose}>Close</button>
          <button className="btn btn-primary" onClick={() => onAdjustBalance(u)}>± Adjust balance</button>
        </div>
      </div>
    </Modal>
  );
}

function Stat({ label, value, color }) {
  return (
    <div>
      <div style={{ fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>{label}</div>
      <div className="mono" style={{ fontSize: 16, fontWeight: 500, color: color || 'var(--fg-0)' }}>{value}</div>
    </div>
  );
}

function KV({ label, value }) {
  return (
    <div style={{ padding: '8px 12px', background: 'var(--bg-2)', borderRadius: 6, border: '1px solid var(--line)' }}>
      <div style={{ fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 3 }}>{label}</div>
      <div style={{ fontSize: 12, color: 'var(--fg-1)' }}>{value}</div>
    </div>
  );
}

function Table({ headers, children }) {
  return (
    <div style={{ maxHeight: 280, overflowY: 'auto', border: '1px solid var(--line)', borderRadius: 6 }}>
      <table style={{ width: '100%' }}>
        <thead>
          <tr style={{ background: 'var(--bg-2)', borderBottom: '1px solid var(--line)' }}>
            {headers.map(h => (
              <th key={h} style={{ padding: '8px 10px', fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', fontWeight: 500, textAlign: 'left', letterSpacing: '0.06em' }}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>{children}</tbody>
      </table>
    </div>
  );
}

function Empty({ msg }) {
  return <div style={{ padding: 24, textAlign: 'center', fontSize: 12, color: 'var(--fg-3)', background: 'var(--bg-2)', borderRadius: 6 }}>{msg}</div>;
}

function AdminPlans() {
  const [plans, setPlans] = React.useState(null);
  const [editing, setEditing] = React.useState(null);
  const [err, setErr] = React.useState(null);

  const load = React.useCallback(async () => {
    try {
      const d = await window.api('/api/dashboard/plans');
      setPlans(d.plans || []);
    } catch (e) { setErr(window.apiErrorMessage(e)); }
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (err) return (
    <div>
      <PageHeader title="Plans"/>
      <div role="alert" className="card" style={{ padding: 16, color: 'var(--err)' }}>{err}</div>
    </div>
  );

  if (!plans) return (
    <div>
      <PageHeader title="Plans"/>
      <div className="card" style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)' }}>
        <Spinner/> <span style={{ marginLeft: 8 }}>Loading…</span>
      </div>
    </div>
  );

  return (
    <div>
      <PageHeader title="Plans & products" subtitle={`${plans.length} plans — click any row to edit.`}/>

      <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
        <table style={{ width: '100%' }}>
          <thead>
            <tr style={{ background: 'var(--bg-2)', borderBottom: '1px solid var(--line)' }}>
              {['ID', 'Name', 'Price', 'GB / Speed', 'Label', 'Popular', ''].map(h => (
                <th key={h} style={{ padding: '10px 16px', fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', fontWeight: 500, textAlign: 'left' }}>{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {plans.map(p => (
              <tr key={p.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                <td style={{ padding: '12px 16px' }} className="mono"><span style={{ fontSize: 12, color: 'var(--fg-2)' }}>{p.id}</span></td>
                <td style={{ padding: '12px 16px', fontSize: 13 }}>{p.name}</td>
                <td style={{ padding: '12px 16px' }} className="mono"><span style={{ fontSize: 13 }}>${Number(p.price).toFixed(2)}</span></td>
                <td style={{ padding: '12px 16px', fontSize: 13, color: 'var(--fg-2)' }}>{p.gb}</td>
                <td style={{ padding: '12px 16px' }}><span className="chip">{p.label}</span></td>
                <td style={{ padding: '12px 16px' }}>{p.popular ? <span className="chip chip-accent">★</span> : <span style={{ color: 'var(--fg-3)' }}>—</span>}</td>
                <td style={{ padding: '12px 16px' }}>
                  <button className="btn btn-ghost btn-sm" onClick={() => setEditing(p)}>Edit</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {editing && (
        <EditPlanModal
          plan={editing}
          onClose={() => setEditing(null)}
          onSaved={() => { setEditing(null); load(); }}
        />
      )}
    </div>
  );
}

function EditPlanModal({ plan, onClose, onSaved }) {
  const [name, setName]       = React.useState(plan.name);
  const [price, setPrice]     = React.useState(plan.price);
  const [gb, setGb]           = React.useState(plan.gb);
  const [label, setLabel]     = React.useState(plan.label);
  const [popular, setPopular] = React.useState(!!plan.popular);
  const [features, setFeatures] = React.useState((plan.features || []).join('\n'));
  const [busy, setBusy]       = React.useState(false);
  const [err, setErr]         = React.useState(null);

  const submit = async (e) => {
    e.preventDefault();
    setBusy(true); setErr(null);
    try {
      const body = {
        name,
        price: Number(price),
        gb,
        label,
        popular,
        features: features.split('\n').map(s => s.trim()).filter(Boolean).slice(0, 12),
      };
      await window.api(`/api/admin/plans/${plan.id}`, { method: 'PATCH', body });
      onSaved();
    } catch (e) {
      setErr(window.apiErrorMessage(e));
      setBusy(false);
    }
  };

  return (
    <Modal onClose={onClose} title={`Edit plan · ${plan.id}`}>
      <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <Field label="Name">
          <input value={name} onChange={e => setName(e.target.value)} style={{ width: '100%' }} required maxLength={80}/>
        </Field>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          <Field label="Price (USD)">
            <input type="number" step="0.01" min="0" value={price} onChange={e => setPrice(e.target.value)} style={{ width: '100%' }} required/>
          </Field>
          <Field label="GB / Speed">
            <input value={gb} onChange={e => setGb(e.target.value)} style={{ width: '100%' }} placeholder="e.g. 10 GB" maxLength={32}/>
          </Field>
        </div>
        <Field label="Label">
          <input value={label} onChange={e => setLabel(e.target.value)} style={{ width: '100%' }} maxLength={32}/>
        </Field>
        <label style={{ display: 'flex', gap: 8, alignItems: 'center', fontSize: 13 }}>
          <input type="checkbox" checked={popular} onChange={e => setPopular(e.target.checked)}/>
          Show as "Most popular"
        </label>
        <Field label="Features (one per line)">
          <textarea
            value={features}
            onChange={e => setFeatures(e.target.value)}
            rows={6}
            style={{ width: '100%', resize: 'vertical', fontFamily: 'inherit' }}
            placeholder="Unlimited residential for 1 hour&#10;Worldwide pool&#10;HTTP / HTTPS"
          />
        </Field>
        {err && <div role="alert" style={{ fontSize: 12, color: 'var(--err)' }}>{err}</div>}
        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Cancel</button>
          <button type="submit" className="btn btn-primary" disabled={busy}>{busy ? 'Saving…' : 'Save changes'}</button>
        </div>
      </form>
    </Modal>
  );
}

// `Field` is defined once, by the first component that uses it (Dashboard.jsx).
// CheckoutAdmin.jsx is loaded after it in index.html, so the global is available.

function AdminRevenue() {
  return (
    <div>
      <PageHeader title="Revenue" subtitle="Revenue metrics live on the Operations page."/>
      <div className="card" style={{ padding: 48, textAlign: 'center' }}>
        <div style={{ fontSize: 14, color: 'var(--fg-1)', marginBottom: 6 }}>See Operations for real revenue data.</div>
        <div style={{ fontSize: 12, color: 'var(--fg-3)' }}>
          The Ops page shows deposits, plan sales, and a 30-day revenue chart from your live transaction log.
        </div>
      </div>
    </div>
  );
}

function AdminOxapay() {
  const [data, setData] = React.useState(null);
  const [err, setErr]   = React.useState(null);

  const load = React.useCallback(async () => {
    try { setData(await window.api('/api/admin/oxapay')); }
    catch (e) { setErr(window.apiErrorMessage(e)); }
  }, []);
  React.useEffect(() => { load(); }, [load]);

  // Auto-refresh every 10 s so admins watch payments come in live
  React.useEffect(() => {
    const t = setInterval(load, 10_000);
    return () => clearInterval(t);
  }, [load]);

  const fmt$ = (n) => `$${Number(n || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
  const fmtDate = (iso) => {
    if (!iso) return '—';
    const d = new Date(iso + (iso.endsWith('Z') ? '' : 'Z'));
    return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
  };
  const fmtRelative = (iso) => {
    if (!iso) return '';
    const ms = Date.now() - new Date(iso + (iso.endsWith('Z') ? '' : 'Z')).getTime();
    const s = Math.floor(ms / 1000);
    if (s < 60)    return `${s}s ago`;
    if (s < 3600)  return `${Math.floor(s / 60)}m ago`;
    if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
    return `${Math.floor(s / 86400)}d ago`;
  };

  if (err) return (
    <div>
      <PageHeader title="OxaPay monitor"/>
      <div role="alert" style={{
        fontSize: 13, color: 'var(--err)',
        background: 'color-mix(in oklab, var(--err) 10%, transparent)',
        border: '1px solid color-mix(in oklab, var(--err) 30%, transparent)',
        padding: '12px 16px', borderRadius: 8,
      }}>{err}</div>
    </div>
  );

  if (!data) return (
    <div>
      <PageHeader title="OxaPay monitor"/>
      <div className="card" style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)' }}>
        <Spinner/> <span style={{ marginLeft: 8 }}>Loading…</span>
      </div>
    </div>
  );

  const cfg = data.config;
  const s = data.stats;
  const cards = [
    { k: 'Today',         v: fmt$(s.today_total), sub: `${s.today_count} payment${s.today_count === 1 ? '' : 's'}` },
    { k: 'Pending',       v: fmt$(s.pending_total), sub: `${s.pending_count} confirming` },
    { k: 'Last 30 days',  v: fmt$(s.month_total), sub: `${s.month_count} payment${s.month_count === 1 ? '' : 's'}` },
    { k: 'Failed (24h)',  v: String(s.failed_24h), sub: 'awaiting retry' },
  ];

  return (
    <div>
      <PageHeader
        title="OxaPay monitor"
        subtitle="Live crypto payment activity. Updates every 10 seconds."
        actions={
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            {cfg.configured ? (
              <span className="chip chip-ok"><span className="dot" style={{ background: 'var(--ok)' }}/> Gateway live{cfg.sandbox ? ' · sandbox' : ''}</span>
            ) : (
              <span className="chip chip-warn"><span className="dot" style={{ background: 'var(--warn)' }}/> Gateway not configured</span>
            )}
          </div>
        }
      />

      {!cfg.configured && (
        <div role="alert" style={{
          fontSize: 12, color: 'var(--warn)',
          background: 'color-mix(in oklab, var(--warn) 10%, transparent)',
          border: '1px solid color-mix(in oklab, var(--warn) 30%, transparent)',
          padding: '10px 14px', borderRadius: 8, marginBottom: 16,
          display: 'flex', alignItems: 'center', gap: 10,
        }}>
          <Icon name="alert" size={14}/>
          <div>
            <div style={{ color: 'var(--fg-1)', marginBottom: 2 }}>OxaPay is running in MOCK mode.</div>
            <div>Set <code>OXAPAY_MERCHANT_API_KEY</code> and <code>OXAPAY_CALLBACK_URL</code> in your <code>.env</code> file and restart to enable real crypto payments.</div>
          </div>
        </div>
      )}

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginBottom: 24 }}>
        {cards.map(c => (
          <div key={c.k} className="card" style={{ padding: 18 }}>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 8 }}>{c.k}</div>
            <div className="mono" style={{ fontSize: 22, fontWeight: 500 }}>{c.v}</div>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 4 }}>{c.sub}</div>
          </div>
        ))}
      </div>

      {/* Config inspector */}
      <div className="card" style={{ padding: 0, overflow: 'hidden', marginBottom: 16 }}>
        <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ fontSize: 13, fontWeight: 500 }}>Gateway configuration</div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 0 }}>
          <Cfg label="API key"      value={cfg.key_length > 0 ? `••• ${cfg.key_length} chars` : 'NOT SET'} ok={cfg.key_length > 0}/>
          <Cfg label="Callback URL" value={cfg.callback || 'NOT SET'} ok={Boolean(cfg.callback)} mono/>
          <Cfg label="Sandbox mode" value={cfg.sandbox ? 'ON (test funds)' : 'OFF (real funds)'} ok={!cfg.sandbox}/>
        </div>
      </div>

      {/* Recent topup orders */}
      <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
        <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--line)' }}>
          <div style={{ fontSize: 13, fontWeight: 500 }}>Recent top-ups</div>
        </div>
        {data.orders.length === 0 ? (
          <div style={{ padding: 32, textAlign: 'center', fontSize: 13, color: 'var(--fg-3)' }}>No top-ups yet.</div>
        ) : (
          <table style={{ width: '100%' }}>
            <thead>
              <tr style={{ background: 'var(--bg-2)', borderBottom: '1px solid var(--line)' }}>
                {['Order', 'User', 'Amount', 'Tx hash', 'Status', 'Created', 'Paid', ''].map(h => (
                  <th key={h} style={{ padding: '10px 14px', fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', fontWeight: 500, textAlign: 'left' }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {data.orders.map(o => (
                <tr key={o.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                  <td style={{ padding: '10px 14px' }}><span className="mono" style={{ fontSize: 11, color: 'var(--fg-2)' }}>{o.id}</span></td>
                  <td style={{ padding: '10px 14px', fontSize: 12 }} className="mono">{o.email}</td>
                  <td style={{ padding: '10px 14px' }}>
                    <span className="mono" style={{ fontSize: 13, color: o.status === 'paid' ? 'var(--ok)' : 'var(--fg-1)' }}>{fmt$(o.amount_usd)}</span>
                  </td>
                  <td style={{ padding: '10px 14px' }}>
                    {o.tx_hash
                      ? <span className="mono" style={{ fontSize: 11, color: 'var(--accent)' }}>{String(o.tx_hash).slice(0, 18)}…</span>
                      : <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>—</span>}
                  </td>
                  <td style={{ padding: '10px 14px' }}>
                    <span className={
                      o.status === 'paid'        ? 'chip chip-ok' :
                      o.status === 'confirming'  ? 'chip chip-warn' :
                      o.status === 'pending'     ? 'chip chip-warn' :
                      'chip chip-err'
                    } style={{ fontSize: 10 }}>{o.status}</span>
                  </td>
                  <td style={{ padding: '10px 14px', fontSize: 11, color: 'var(--fg-3)' }} title={fmtDate(o.created_at)}>
                    {fmtRelative(o.created_at)}
                  </td>
                  <td style={{ padding: '10px 14px', fontSize: 11, color: 'var(--fg-3)' }} title={o.paid_at ? fmtDate(o.paid_at) : ''}>
                    {o.paid_at ? fmtRelative(o.paid_at) : '—'}
                  </td>
                  <td style={{ padding: '10px 14px' }}>
                    {(o.status === 'pending' || o.status === 'confirming') && (
                      <ConfirmBtn orderId={o.id} amount={o.amount_usd} email={o.email} onDone={load}/>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

function ConfirmBtn({ orderId, amount, email, onDone }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr]   = React.useState(null);

  const click = async () => {
    const msg = `Force-confirm ${orderId} for $${Number(amount).toFixed(2)} → ${email}?\n\n`
              + `This bypasses the OxaPay webhook and credits the user immediately. `
              + `Use only when the real webhook didn't arrive, or for testing.`;
    if (!window.confirm(msg)) return;
    setBusy(true);
    setErr(null);
    try {
      await window.api(`/api/admin/oxapay/orders/${orderId}/confirm`, { method: 'POST' });
      onDone?.();
    } catch (e) {
      setErr(window.apiErrorMessage(e));
    } finally {
      setBusy(false);
    }
  };

  return (
    <div>
      <button
        className="btn btn-ghost btn-sm"
        disabled={busy}
        onClick={click}
        style={{
          fontSize: 11, padding: '4px 10px',
          color: busy ? 'var(--fg-3)' : 'var(--accent)',
        }}
        title="Force-confirm this top-up (admin override)"
      >
        {busy ? '…' : 'Confirm'}
      </button>
      {err && <div style={{ fontSize: 10, color: 'var(--err)', marginTop: 4 }}>{err}</div>}
    </div>
  );
}

function Cfg({ label, value, ok, mono }) {
  return (
    <div style={{ padding: '14px 20px', borderRight: '1px solid var(--line)', borderTop: '0' }}>
      <div style={{ fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6 }}>{label}</div>
      <div
        className={mono ? 'mono' : ''}
        style={{
          fontSize: 12,
          color: ok ? 'var(--ok)' : 'var(--warn)',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}
        title={value}
      >{value}</div>
    </div>
  );
}

function AdminTickets() {
  const [tickets, setTickets] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const [openId, setOpenId] = React.useState(null);

  const load = React.useCallback(async () => {
    try {
      const d = await window.api('/api/admin/tickets');
      setTickets(d.tickets || []);
    } catch (e) {
      setErr(window.apiErrorMessage(e));
      setTickets([]);
    }
  }, []);
  React.useEffect(() => { load(); }, [load]);

  const setStatus = async (id, status) => {
    try {
      await window.api(`/api/admin/tickets/${id}`, { method: 'PATCH', body: { status } });
      await load();
    } catch (e) {
      setErr(window.apiErrorMessage(e));
    }
  };

  const open   = (tickets || []).filter(t => t.status === 'open').length;
  const ago    = (iso) => timeAgo(iso);

  return (
    <div>
      <PageHeader
        title="Support queue"
        subtitle={tickets ? `${open} open · ${tickets.length} total` : 'Loading…'}
      />

      {err && (
        <div role="alert" style={{
          fontSize: 12, color: 'var(--err)',
          background: 'color-mix(in oklab, var(--err) 10%, transparent)',
          border: '1px solid color-mix(in oklab, var(--err) 30%, transparent)',
          padding: '9px 12px', borderRadius: 8, marginBottom: 16,
          display: 'flex', alignItems: 'center', gap: 8,
        }}>
          <Icon name="alert" size={13}/> {err}
        </div>
      )}

      {tickets === null ? (
        <div className="card" style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)', fontSize: 13 }}>
          <Spinner/> <span style={{ marginLeft: 8 }}>Loading…</span>
        </div>
      ) : tickets.length === 0 ? (
        <div className="card" style={{ padding: 48, textAlign: 'center' }}>
          <div style={{ fontSize: 14, color: 'var(--fg-1)', marginBottom: 6 }}>No tickets in the queue.</div>
        </div>
      ) : (
        <div className="card">
          {tickets.map((t, i) => (
            <div key={t.id} style={{ display: 'flex', alignItems: 'center', gap: 16, padding: 20, borderTop: i > 0 ? '1px solid var(--line-soft)' : 'none' }}>
              <button
                onClick={() => setOpenId(t.id)}
                style={{ display: 'flex', alignItems: 'center', gap: 16, flex: 1, background: 'transparent', textAlign: 'left', cursor: 'pointer' }}
              >
                <span className="mono" style={{ fontSize: 12, color: 'var(--fg-2)', width: 60 }}>#{t.id}</span>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 14 }}>{t.subject}</div>
                  <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 2 }}>{t.email} · {ago(t.created_at)}</div>
                </div>
                <span className={t.status === 'open' ? 'chip chip-warn' : t.status === 'closed' ? 'chip chip-ok' : 'chip'}>{t.status}</span>
              </button>
              <div style={{ display: 'flex', gap: 6 }}>
                {t.status !== 'closed' && (
                  <button className="btn btn-ghost btn-sm" title="Close" onClick={() => setStatus(t.id, 'closed')}>
                    <Icon name="check" size={12}/>
                  </button>
                )}
                {t.status === 'closed' && (
                  <button className="btn btn-ghost btn-sm" title="Re-open" onClick={() => setStatus(t.id, 'open')}>
                    <Icon name="refresh" size={12}/>
                  </button>
                )}
              </div>
            </div>
          ))}
        </div>
      )}

      {openId !== null && (
        <TicketThread
          ticketId={openId}
          api="/api/admin/tickets"
          postAs="admin"
          onClose={() => { setOpenId(null); load(); }}
        />
      )}
    </div>
  );
}

function AdminCoupons() {
  const [coupons, setCoupons] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const [createOpen, setCreateOpen] = React.useState(false);
  const [detailCode, setDetailCode] = React.useState(null);

  const load = React.useCallback(async () => {
    try {
      const d = await window.api('/api/admin/coupons');
      setCoupons(d.coupons || []);
    } catch (e) { setErr(window.apiErrorMessage(e)); }
  }, []);
  React.useEffect(() => { load(); }, [load]);

  const toggleActive = async (code, next) => {
    try {
      await window.api(`/api/admin/coupons/${encodeURIComponent(code)}`, {
        method: 'PATCH', body: { active: next },
      });
      load();
    } catch (e) { setErr(window.apiErrorMessage(e)); }
  };

  const remove = async (code) => {
    if (!confirm(`Delete coupon ${code}? This can't be undone.`)) return;
    try {
      await window.api(`/api/admin/coupons/${encodeURIComponent(code)}`, { method: 'DELETE' });
      load();
    } catch (e) { setErr(window.apiErrorMessage(e)); }
  };

  const fmtDate = (iso) => {
    if (!iso) return '—';
    const d = new Date(iso + (iso.endsWith('Z') ? '' : 'Z'));
    return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
  };

  return (
    <div>
      <PageHeader
        title="Coupons & promotions"
        subtitle={coupons ? `${coupons.length} code${coupons.length === 1 ? '' : 's'} · share as /?ref=CODE to track clicks` : 'Loading…'}
        actions={<button className="btn btn-primary btn-sm" onClick={() => setCreateOpen(true)}><Icon name="plus" size={12}/> New coupon</button>}
      />

      {err && (
        <div role="alert" style={{
          fontSize: 12, color: 'var(--err)',
          background: 'color-mix(in oklab, var(--err) 10%, transparent)',
          border: '1px solid color-mix(in oklab, var(--err) 30%, transparent)',
          padding: '9px 12px', borderRadius: 8, marginBottom: 16,
        }}>{err}</div>
      )}

      {coupons === null ? (
        <div className="card" style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)' }}>
          <Spinner/> <span style={{ marginLeft: 8 }}>Loading…</span>
        </div>
      ) : coupons.length === 0 ? (
        <div className="card" style={{ padding: 48, textAlign: 'center' }}>
          <div style={{ fontSize: 14, color: 'var(--fg-1)', marginBottom: 6 }}>No coupons yet.</div>
          <div style={{ fontSize: 12, color: 'var(--fg-3)', marginBottom: 14 }}>
            Create your first code, then share it as <code style={{ background: 'var(--bg-2)', padding: '2px 6px', borderRadius: 4 }}>yoursite.com/?ref=CODE</code>
          </div>
          <button className="btn btn-primary btn-sm" onClick={() => setCreateOpen(true)}>Create coupon</button>
        </div>
      ) : (
        <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
          <table style={{ width: '100%' }}>
            <thead>
              <tr style={{ background: 'var(--bg-2)', borderBottom: '1px solid var(--line)' }}>
                {['Code', 'Discount', 'Views', 'Redemptions', 'Conv %', 'Saved', 'Limit', 'Expires', 'Status', ''].map(h => (
                  <th key={h} style={{ padding: '10px 14px', fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', fontWeight: 500, textAlign: 'left' }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {coupons.map(c => {
                const conv = c.view_count > 0 ? ((c.redemptions / c.view_count) * 100).toFixed(1) : '—';
                const expired = c.expires_at && new Date(c.expires_at) <= new Date();
                const exhausted = c.max_uses != null && c.used_count >= c.max_uses;
                const status = !c.active ? 'disabled' : expired ? 'expired' : exhausted ? 'exhausted' : 'active';
                const chipCls = status === 'active' ? 'chip chip-ok' : status === 'disabled' ? 'chip' : 'chip chip-warn';
                return (
                  <tr key={c.code} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                    <td style={{ padding: '12px 14px' }}>
                      <button
                        className="mono"
                        onClick={() => setDetailCode(c.code)}
                        style={{ background: 'transparent', fontSize: 13, color: 'var(--accent)', letterSpacing: '0.06em', cursor: 'pointer' }}
                      >{c.code}</button>
                    </td>
                    <td style={{ padding: '12px 14px' }} className="mono"><span style={{ fontSize: 13 }}>{c.discount_pct}%</span></td>
                    <td style={{ padding: '12px 14px' }} className="mono"><span style={{ fontSize: 13 }}>{c.view_count.toLocaleString()}</span></td>
                    <td style={{ padding: '12px 14px' }} className="mono"><span style={{ fontSize: 13, color: 'var(--ok)' }}>{c.redemptions}</span></td>
                    <td style={{ padding: '12px 14px' }} className="mono"><span style={{ fontSize: 12, color: 'var(--fg-2)' }}>{conv}{conv !== '—' && '%'}</span></td>
                    <td style={{ padding: '12px 14px' }} className="mono"><span style={{ fontSize: 12, color: 'var(--fg-2)' }}>${Number(c.total_saved_usd).toFixed(2)}</span></td>
                    <td style={{ padding: '12px 14px', fontSize: 12, color: 'var(--fg-2)' }}>{c.max_uses != null ? `${c.used_count} / ${c.max_uses}` : '∞'}</td>
                    <td style={{ padding: '12px 14px', fontSize: 12, color: 'var(--fg-2)' }}>{fmtDate(c.expires_at)}</td>
                    <td style={{ padding: '12px 14px' }}><span className={chipCls}>{status}</span></td>
                    <td style={{ padding: '12px 14px', display: 'flex', gap: 4 }}>
                      {c.active
                        ? <button className="btn btn-ghost btn-sm" title="Disable" onClick={() => toggleActive(c.code, false)}>Off</button>
                        : <button className="btn btn-ghost btn-sm" title="Enable"  onClick={() => toggleActive(c.code, true)}>On</button>
                      }
                      <button className="btn btn-ghost btn-sm" title="Delete" onClick={() => remove(c.code)}>
                        <Icon name="trash" size={12}/>
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {createOpen && (
        <CreateCouponModal onClose={() => setCreateOpen(false)} onCreated={() => { setCreateOpen(false); load(); }}/>
      )}

      {detailCode && (
        <CouponDetailModal code={detailCode} onClose={() => setDetailCode(null)}/>
      )}
    </div>
  );
}

function CreateCouponModal({ onClose, onCreated }) {
  const [code, setCode]     = React.useState('');
  const [pct, setPct]       = React.useState(10);
  const [maxUses, setMaxUses] = React.useState('');
  const [expiresAt, setExpiresAt] = React.useState('');
  const [note, setNote]     = React.useState('');
  const [busy, setBusy]     = React.useState(false);
  const [err, setErr]       = React.useState(null);

  const submit = async (e) => {
    e.preventDefault();
    setErr(null);
    const clean = code.trim().toUpperCase();
    if (!/^[A-Z0-9_-]{2,32}$/.test(clean)) { setErr('Code must be 2-32 chars, A-Z / 0-9 / _ / -'); return; }
    const p = Number(pct);
    if (!Number.isFinite(p) || p <= 0 || p > 90) { setErr('Discount must be between 0.1 and 90.'); return; }
    setBusy(true);
    try {
      const body = { code: clean, discount_pct: p };
      if (maxUses !== '') body.max_uses = Number(maxUses);
      if (expiresAt !== '') body.expires_at = new Date(expiresAt).toISOString();
      if (note.trim()) body.note = note.trim();
      await window.api('/api/admin/coupons', { method: 'POST', body });
      onCreated();
    } catch (e) {
      if (e?.status === 409) setErr('That code already exists.');
      else setErr(window.apiErrorMessage(e));
      setBusy(false);
    }
  };

  return (
    <Modal onClose={onClose} title="New coupon">
      <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <Field label="Code">
          <input
            value={code}
            onChange={e => setCode(e.target.value.toUpperCase())}
            placeholder="e.g. LAUNCH"
            maxLength={32}
            required
            className="mono"
            style={{ width: '100%', letterSpacing: '0.08em' }}
            autoFocus
          />
        </Field>
        <Field label="Discount %">
          <input
            type="number" min="0.1" max="90" step="0.1"
            value={pct} onChange={e => setPct(e.target.value)}
            required style={{ width: '100%' }}
          />
        </Field>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          <Field label="Max uses (optional)">
            <input type="number" min="1" value={maxUses} onChange={e => setMaxUses(e.target.value)} placeholder="∞" style={{ width: '100%' }}/>
          </Field>
          <Field label="Expires (optional)">
            <input type="datetime-local" value={expiresAt} onChange={e => setExpiresAt(e.target.value)} style={{ width: '100%' }}/>
          </Field>
        </div>
        <Field label="Note (optional, admin-only)">
          <input value={note} onChange={e => setNote(e.target.value)} placeholder="e.g. October launch promo" maxLength={200} style={{ width: '100%' }}/>
        </Field>
        <div style={{ fontSize: 12, color: 'var(--fg-2)', background: 'var(--bg-2)', padding: 12, borderRadius: 8, border: '1px solid var(--line)' }}>
          <div style={{ marginBottom: 4 }}>Share URL will be:</div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--accent)' }}>
            {window.location.origin}/?ref={code.trim().toUpperCase() || 'CODE'}
          </div>
        </div>
        {err && <div role="alert" style={{ fontSize: 12, color: 'var(--err)' }}>{err}</div>}
        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Cancel</button>
          <button type="submit" className="btn btn-primary" disabled={busy}>{busy ? 'Creating…' : 'Create coupon'}</button>
        </div>
      </form>
    </Modal>
  );
}

function CouponDetailModal({ code, onClose }) {
  const [data, setData] = React.useState(null);
  const [err, setErr]   = React.useState(null);
  const [copied, setCopied] = React.useState(false);

  React.useEffect(() => {
    window.api(`/api/admin/coupons/${encodeURIComponent(code)}`)
      .then(setData)
      .catch(e => setErr(window.apiErrorMessage(e)));
  }, [code]);

  const shareUrl = `${window.location.origin}/?ref=${code}`;

  const copy = async () => {
    try { await navigator.clipboard.writeText(shareUrl); } catch (_) {}
    setCopied(true);
    setTimeout(() => setCopied(false), 1200);
  };

  const fmtDate = (iso) => {
    if (!iso) return '—';
    const d = new Date(iso + (iso.endsWith('Z') ? '' : 'Z'));
    return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
  };

  return (
    <Modal onClose={onClose} title={`Coupon · ${code}`}>
      {err && <div role="alert" style={{ fontSize: 12, color: 'var(--err)' }}>{err}</div>}
      {!data ? (
        <div style={{ padding: 24, textAlign: 'center', color: 'var(--fg-3)' }}>
          <Spinner/> <span style={{ marginLeft: 8 }}>Loading…</span>
        </div>
      ) : (
        <>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10, marginBottom: 16 }}>
            <div style={{ padding: 12, background: 'var(--bg-2)', borderRadius: 8, border: '1px solid var(--line)' }}>
              <div style={{ fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Views</div>
              <div className="mono" style={{ fontSize: 20, fontWeight: 500 }}>{data.coupon.view_count}</div>
            </div>
            <div style={{ padding: 12, background: 'var(--bg-2)', borderRadius: 8, border: '1px solid var(--line)' }}>
              <div style={{ fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Redemptions</div>
              <div className="mono" style={{ fontSize: 20, fontWeight: 500, color: 'var(--ok)' }}>{data.coupon.used_count}</div>
            </div>
            <div style={{ padding: 12, background: 'var(--bg-2)', borderRadius: 8, border: '1px solid var(--line)' }}>
              <div style={{ fontSize: 10, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Saved by users</div>
              <div className="mono" style={{ fontSize: 20, fontWeight: 500 }}>${Number(data.coupon.total_saved_usd).toFixed(2)}</div>
            </div>
          </div>

          <div style={{ fontSize: 11, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6 }}>Share URL</div>
          <div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
            <div className="mono" style={{
              flex: 1, padding: '10px 12px', background: 'var(--bg-2)',
              border: '1px solid var(--line)', borderRadius: 8, fontSize: 11,
              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            }}>{shareUrl}</div>
            <button className="btn btn-ghost btn-sm" onClick={copy} style={{ color: copied ? 'var(--ok)' : undefined }}>
              <Icon name={copied ? 'check' : 'copy'} size={12}/>
            </button>
          </div>

          {data.coupon.note && (
            <div style={{ fontSize: 12, color: 'var(--fg-2)', marginBottom: 16, padding: 10, background: 'var(--bg-2)', borderRadius: 6 }}>
              Note: {data.coupon.note}
            </div>
          )}

          <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 8 }}>Recent redemptions</div>
          {data.redemptions.length === 0 ? (
            <div style={{ fontSize: 12, color: 'var(--fg-3)', padding: 20, textAlign: 'center', background: 'var(--bg-2)', borderRadius: 8 }}>
              No redemptions yet.
            </div>
          ) : (
            <div style={{ maxHeight: 240, overflowY: 'auto', border: '1px solid var(--line)', borderRadius: 8 }}>
              <table style={{ width: '100%' }}>
                <tbody>
                  {data.redemptions.map(r => (
                    <tr key={r.id} style={{ borderBottom: '1px solid var(--line-soft)' }}>
                      <td style={{ padding: '8px 12px', fontSize: 11, color: 'var(--fg-3)', whiteSpace: 'nowrap' }}>{fmtDate(r.created_at)}</td>
                      <td style={{ padding: '8px 12px', fontSize: 12 }} className="mono">{r.user_email}</td>
                      <td style={{ padding: '8px 12px' }}><span className="chip" style={{ fontSize: 10 }}>{r.plan_id}</span></td>
                      <td style={{ padding: '8px 12px', textAlign: 'right' }} className="mono">
                        <span style={{ fontSize: 12, color: 'var(--ok)' }}>−${Number(r.saved_usd).toFixed(2)}</span>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </>
      )}
    </Modal>
  );
}

function AdminLogs() {
  const [logs, setLogs] = React.useState(null);
  const [err, setErr] = React.useState(null);

  React.useEffect(() => {
    window.api('/api/admin/logs')
      .then(d => setLogs(d.logs || []))
      .catch(e => { setErr(window.apiErrorMessage(e)); setLogs([]); });
  }, []);

  // Color by event type
  const kindFor = (ev) => {
    if (ev.startsWith('admin.') || ev.includes('fail') || ev.includes('error')) return 'warn';
    if (ev.includes('paid') || ev.includes('register')) return 'ok';
    return 'info';
  };

  const fmtTime = (iso) => {
    if (!iso) return '';
    const d = new Date(iso + (iso.endsWith('Z') ? '' : 'Z'));
    return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
  };

  return (
    <div>
      <PageHeader title="System logs" subtitle="Audit log of recent events."/>
      {err && (
        <div role="alert" style={{
          fontSize: 12, color: 'var(--err)',
          background: 'color-mix(in oklab, var(--err) 10%, transparent)',
          border: '1px solid color-mix(in oklab, var(--err) 30%, transparent)',
          padding: '9px 12px', borderRadius: 8, marginBottom: 16,
          display: 'flex', alignItems: 'center', gap: 8,
        }}>
          <Icon name="alert" size={13}/> {err}
        </div>
      )}
      <div className="card" style={{ padding: 20, background: '#050709' }}>
        <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 12, lineHeight: 1.8 }}>
          {logs === null ? (
            <div style={{ color: 'var(--fg-3)' }}>Loading…</div>
          ) : logs.length === 0 ? (
            <div style={{ color: 'var(--fg-3)' }}>No events yet.</div>
          ) : logs.map(l => {
            const k = kindFor(l.event);
            const tag = k === 'warn' ? '[WARN]' : k === 'ok' ? '[OK]' : '[INFO]';
            const color = k === 'warn' ? 'var(--warn)' : k === 'ok' ? 'var(--ok)' : 'var(--accent)';
            const detail = l.detail ? JSON.stringify(l.detail).slice(0, 140) : '';
            return (
              <div key={l.id} style={{ display: 'flex', gap: 12 }}>
                <span style={{ color: 'var(--fg-3)' }}>{fmtTime(l.ts)}</span>
                <span style={{ color, width: 56 }}>{tag}</span>
                <span style={{ color: 'var(--fg-1)', flex: 1 }}>
                  {l.event}{l.user_id ? ` · uid=${l.user_id}` : ''}{detail ? ` · ${detail}` : ''}
                </span>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

window.Checkout = Checkout;
window.Admin = Admin;
