/* WC2026 — quick-bet version: tap odds, enter stake, place instantly */
const { useState, useEffect, useRef, useCallback } = React;
const WC = window.WC;
const E  = window.WCEngine;

/* ── Icons ─────────────────────────────────────────────── */
const Ic = {
  ball:    p => (<svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.7"/><path d="M12 7.5l2.6 1.9-1 3.1h-3.2l-1-3.1L12 7.5z" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round"/><path d="M12 3v2.2M5.2 8.4l1.9 1.2M5.6 17l1.8-1.4M18.4 17l-1.8-1.4M18.8 8.4l-1.9 1.2M9 20l1-2.2m4 2.2l-1-2.2" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>),
  ticket:  p => (<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 8a2 2 0 012-2h14a2 2 0 012 2v1.5a1.7 1.7 0 000 3.4V16a2 2 0 01-2 2H5a2 2 0 01-2-2v-2.6a1.7 1.7 0 000-3.4V8z" stroke="currentColor" strokeWidth="1.6"/><path d="M14 6v12" stroke="currentColor" strokeWidth="1.6" strokeDasharray="2 2.4"/></svg>),
  trophy:  p => (<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M7 4h10v4a5 5 0 01-10 0V4z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/><path d="M7 6H4.5v1A3 3 0 007 10M17 6h2.5v1a3 3 0 01-2.5 3M12 13v3m-3 4h6m-5 0a3 3 0 013-3 3 3 0 013 3" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  whistle: p => (<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 12a5 5 0 005 5h2.2l4.6 3v-4.5A5 5 0 0017 12V9H3v3z" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round"/><circle cx="8" cy="13" r="1.6" stroke="currentColor" strokeWidth="1.4"/><path d="M17 9l3.5-2M17 11h4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/></svg>),
  x:       p => (<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M6 6l12 12M18 6L6 18" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>),
  check:   p => (<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M5 12.5l4.5 4.5L19 7" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  out:     p => (<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M14 4h4a2 2 0 012 2v12a2 2 0 01-2 2h-4M9 8l-4 4 4 4M5 12h10" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>),
};

/* ── Helpers ────────────────────────────────────────────── */
function pts(n) {
  const r = Math.round(n * 100) / 100;
  return Number.isInteger(r)
    ? r.toLocaleString('en-US')
    : r.toLocaleString('en-US', { minimumFractionDigits:2, maximumFractionDigits:2 });
}

function fmtUpdateTime(ms) {
  if (!ms) return 'No settled matches yet';
  return WC.formatTime(new Date(ms).toISOString());
}

function Coin({ size = 15 }) {
  return <span style={{ width:size, height:size, borderRadius:'50%', background:'var(--gold)',
    boxShadow:'inset 0 0 0 2px rgba(0,0,0,.14)', display:'inline-block', flex:'none' }} />;
}

function Badge({ code, size = 38 }) {
  const t = WC.team(code), fs = Math.round(size * .34);
  return (
    <span className="badge" style={{ width:size, height:size, background:t.primary }}>
      <span className="corner" style={{ borderWidth:`0 ${size*.42}px ${size*.42}px 0`, borderColor:`transparent ${t.accent} transparent transparent` }} />
      <span className="code" style={{ color:t.text, fontSize:fs }}>{t.code}</span>
    </span>
  );
}

function FlagBadge({ code, size = 38 }) {
  const [err, setErr] = useState(false);
  const t = WC.team(code);
  if (err) return <Badge code={code} size={size} />;
  return (
    <span style={{ width:size, height:size, borderRadius:'50%', overflow:'hidden', display:'inline-block',
      flex:'none', border:'1.5px solid rgba(0,0,0,.1)', boxShadow:'0 1px 5px rgba(0,0,0,.15)', background:t.primary }}>
      <img src={WC.flagUrl(code)} alt={t.name} loading="lazy"
        style={{ width:'100%', height:'100%', objectFit:'cover', display:'block' }}
        onError={() => setErr(true)} />
    </span>
  );
}

function OUBadge({ pick, size = 30 }) {
  const up = pick === 'over';
  return (
    <span style={{ width:size, height:size, borderRadius:'50%', flex:'none',
      background: up?'linear-gradient(135deg,#E61D25,#2A398D)':'linear-gradient(135deg,#2A398D,#3CAC3B)',
      display:'inline-flex', alignItems:'center', justifyContent:'center', boxShadow:'0 1px 5px rgba(0,0,0,.15)' }}>
      <svg viewBox="0 0 14 14" fill="none" style={{ width:size*.54, height:size*.54 }}>
        <path d={up?'M7 11V3M3.5 6.5L7 3l3.5 3.5':'M7 3v8M3.5 7.5L7 11l3.5-3.5'}
          stroke="white" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    </span>
  );
}

function useToasts() {
  const [items, setItems] = useState([]);
  const push = (msg, kind) => {
    const id = Math.random().toString(36).slice(2);
    setItems(s => [...s, { id, msg, kind }]);
    setTimeout(() => setItems(s => s.filter(t => t.id !== id)), 2600);
  };
  const node = (
    <div className="toasts">
      {items.map(t => (
        <div key={t.id} className={'toast '+(t.kind||'')}>
          {t.kind==='good' && <Ic.check style={{width:18,height:18}}/>}
          {t.kind==='bad'  && <Ic.x    style={{width:18,height:18}}/>}
          <span>{t.msg}</span>
        </div>
      ))}
    </div>
  );
  return [node, push];
}

/* ── Odds button ────────────────────────────────────────── */
function Odd({ k, v, on, locked, onClick }) {
  return (
    <button className={'odd'+(on?' on':'')+(locked?' locked':'')}
      onClick={(!on && !locked) ? onClick : undefined}>
      <div className="k">{k}</div>
      <div className="v">{WC.fmtOdds(v)}</div>
    </button>
  );
}

function PopularityBar({ leftLabel, rightLabel, left, right }) {
  const leftAmount = left?.amount || 0;
  const rightAmount = right?.amount || 0;
  const leftCount = left?.count || 0;
  const rightCount = right?.count || 0;
  const total = leftAmount + rightAmount;
  const hasData = total > 0;
  const leftPct = hasData ? Math.round((leftAmount / total) * 100) : 50;
  const rightPct = 100 - leftPct;
  return (
    <div className="popbar">
      <div className="popbar-top">
        <span>{leftLabel} {hasData ? `${leftPct}%` : ''}</span>
        <span className="popbar-empty">{hasData ? '' : 'No picks yet'}</span>
        <span>{rightLabel} {hasData ? `${rightPct}%` : ''}</span>
      </div>
      <div className="popbar-track" title={hasData ? `${leftCount} vs ${rightCount} pending bets` : 'No pending bets yet'}>
        <div className="popbar-fill left" style={{ width:`${leftPct}%` }} />
        <div className="popbar-fill right" style={{ width:`${rightPct}%` }} />
      </div>
    </div>
  );
}

/* ── Bottom nav (3 tabs) ────────────────────────────────── */
function Nav({ tab, setTab, pendingCount }) {
  const items = [
    { id:'matches', label:'Matches',  icon:Ic.ball },
    { id:'bets',    label:'My Bets',  icon:Ic.ticket, badge:pendingCount },
    { id:'ranks',   label:'Ranks',    icon:Ic.trophy },
  ];
  return (
    <div className="nav">
      {items.map(it => {
        const I = it.icon;
        return (
          <button key={it.id} className={tab===it.id?'on':''} onClick={()=>setTab(it.id)}>
            <I /><span className="lbl">{it.label}</span>
            {it.badge ? <span className="dot">{it.badge}</span> : null}
          </button>
        );
      })}
    </div>
  );
}

/* ── Label helpers ──────────────────────────────────────── */
function pickLabel(s) {
  const m = WC.match(s.matchId);
  if (s.market === 'ou') return s.pick==='over' ? `Over ${s.line} goals` : `Under ${s.line} goals`;
  const code = WC.team(s.pick==='home' ? m.home : m.away).code;
  return `${code} ${WC.fmtLine(s.pick==='home' ? s.line : -s.line)} (Handicap)`;
}
function matchLabel(s) {
  const m = WC.match(s.matchId);
  return `${WC.team(m.home).code} v ${WC.team(m.away).code} · ${m.group}`;
}

/* ── Quick Bet Modal ────────────────────────────────────── */
function QuickBetModal({ sel, balance, onClose, onPlaced, toast }) {
  const [stakeStr, setStakeStr] = useState('');
  const [placing, setPlacing]   = useState(false);
  const m = WC.match(sel.matchId);

  const n    = Math.max(0, parseInt(stakeStr, 10) || 0);
  const ret  = n * sel.odds;
  const over = n > balance;
  const can  = n > 0 && !over;

  const add = v => setStakeStr(s => String(Math.min((parseInt(s,10)||0)+v, WC.MAX_BET, balance)));
  const setMax = () => setStakeStr(String(Math.min(WC.MAX_BET, balance)));

  useEffect(() => {
    const viewport = window.visualViewport;
    const updateHeight = () => {
      const height = viewport?.height || window.innerHeight;
      document.documentElement.style.setProperty('--visual-viewport-height', `${height}px`);
    };
    updateHeight();
    viewport?.addEventListener('resize', updateHeight);
    viewport?.addEventListener('scroll', updateHeight);
    return () => {
      viewport?.removeEventListener('resize', updateHeight);
      viewport?.removeEventListener('scroll', updateHeight);
      document.documentElement.style.removeProperty('--visual-viewport-height');
    };
  }, []);

  const place = async () => {
    if (!can || placing) return;
    setPlacing(true);
    const res = await E.placeBets([{ ...sel, stake: n }]);
    setPlacing(false);
    if (!res.ok) { toast(res.msg || 'Error', 'bad'); return; }
    toast(`Bet placed · ${pts(n)} pts`, 'good');
    onPlaced();
  };

  return (
    <div className="modal-bg" onClick={e => e.target===e.currentTarget && onClose()}>
      <div className="sheet">
        <div className="grab" />

        <div className="bet-summary">
          {sel.market==='ou'
            ? <OUBadge pick={sel.pick} size={32}/>
            : <FlagBadge code={sel.pick==='away' ? m.away : m.home} size={32}/>}
          <div className="bet-summary-main">
            <div className="bet-market">{sel.market === 'ou' ? 'Over / Under' : 'Asian Handicap'}</div>
            <div className="bet-pick">{pickLabel(sel)}</div>
            <div className="bet-match">{matchLabel(sel)}</div>
          </div>
          <div className="bet-odds">
            <span>Odds</span>
            {WC.fmtOdds(sel.odds)}
          </div>
          <button className="x-btn" onClick={onClose}><Ic.x style={{width:15,height:15}}/></button>
        </div>

        <div className="bet-section-label">
          <span>Stake</span>
          <span className="balance-pill"><Coin size={11}/> Balance {pts(balance)}</span>
        </div>
        <div className="stake-input bet-stake">
          <Coin size={17}/>
          <input type="number" inputMode="numeric" placeholder="Enter stake" autoFocus
            value={stakeStr}
            onChange={e => {
              const v = e.target.value;
              if (v==='') { setStakeStr(''); return; }
              setStakeStr(String(Math.min(Math.max(0, parseInt(v,10)||0), WC.MAX_BET)));
            }}
            onKeyDown={e => e.key==='Enter' && place()}
          />
          <span className="stake-suffix">pts</span>
        </div>

        <div className="quick bet-quick" style={{ marginTop:8 }}>
          {[100,200,500].map(v => (
            <button key={v} onClick={() => add(v)}>+{v}</button>
          ))}
          <button onClick={setMax}>Max</button>
        </div>

        <div className={'return-card ' + (n <= 0 ? 'return-empty' : over ? 'return-error' : '')}>
          {n <= 0 ? (
            <div>Enter a stake to preview returns</div>
          ) : over ? (
            <div>Stake exceeds your balance ({pts(balance)} pts)</div>
          ) : (
            <div className="return-grid">
              <div>
                <div className="return-label">Returns</div>
                <div className="return-value good">{pts(ret)}</div>
              </div>
              <div>
                <div className="return-label">Profit</div>
                <div className="return-value good">+{pts(ret-n)}</div>
              </div>
            </div>
          )}
        </div>

        <button className="btn btn-grad btn-block bet-confirm" disabled={!can||placing} onClick={place}>
          {placing ? 'Placing bet…' : can ? `Confirm bet ${pts(n)} pts` : 'Enter a stake'}
        </button>
      </div>
    </div>
  );
}

/* ── Onboarding ─────────────────────────────────────────── */
function Onboarding({ leaderboard, onJoin }) {
  const [name, setName]       = useState('');
  const [password, setPassword] = useState('');
  const [joining, setJoining] = useState(false);
  const go = async () => {
    if (!name.trim() || !password.trim() || joining) return;
    setJoining(true); await onJoin(name, password); setJoining(false);
  };
  return (
    <div className="ob">
      <div className="ob-inner">
        <div className="ob-logo">FIFA World Cup 26&trade;</div>
        <h1 className="ob-h">Pick.<br/>Bet.<br/><span className="em">Win.</span></h1>
        <p className="ob-p">Every player starts with <b>3,000</b> points. Read the lines, back your calls on the world&rsquo;s biggest stage, and climb the leaderboard.</p>
        <div className="ob-field">
          <Ic.ball style={{ width:22, height:22, opacity:.9 }}/>
          <input value={name} placeholder="Enter your name" maxLength={16}
            autoCapitalize="characters" spellCheck="false"
            onChange={e => setName(e.target.value.toUpperCase())}
            onKeyDown={e => e.key==='Enter' && go()}/>
        </div>
        <div className="ob-field" style={{ marginTop:10 }}>
          <Ic.ticket style={{ width:22, height:22, opacity:.9 }}/>
          <input type="password" value={password} placeholder="Create or enter password" maxLength={32}
            onChange={e => setPassword(e.target.value)}
            onKeyDown={e => e.key==='Enter' && go()}/>
        </div>
        <button className="ob-btn" onClick={go} disabled={joining}>
          {joining ? 'Signing in…' : 'Register / Login →'}
        </button>
        {leaderboard.length > 0 && (
          <div className="ob-leaderboard">
            <div className="ob-board-title">
              <span>Top 10 Leaderboard</span><span>W / D / L</span>
            </div>
            {leaderboard.slice(0,10).map((r,i) => (
              <div className="ob-rank-row" key={r.name}>
                <span className="ob-rank-no">{i+1}</span>
                <span className="ob-rank-name">{r.name}</span>
                <span className="ob-rank-wdl">{r.wins} / {r.draws} / {r.losses}</span>
                <strong>{pts(r.net)}</strong>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* ── Header ─────────────────────────────────────────────── */
function Header({ player, onLogout, big, subtitle }) {
  return (
    <div className="hd">
      <div className="hd-row">
        <div className="brand">WC26 Pick&amp;Win<small>FIFA WORLD CUP 2026</small></div>
        <div className="hd-spacer"/>
        <div className="hd-chip"><span className="coin"/>{pts(player.balance)}</div>
        <button className="icon-btn" title="Switch player"  onClick={onLogout}><Ic.out/></button>
      </div>
      {big && (
        <div className="bal-hero">
          <div>
            <div className="bal-lbl">Available Balance</div>
            <div className="bal-big">{pts(player.balance)}</div>
          </div>
          <div className="bal-sub">{subtitle}</div>
        </div>
      )}
    </div>
  );
}

/* ── Market odds ────────────────────────────────────────── */
function MarketOdds({ m, myBets, openBet, locked, popularity }) {
  // Same match and market: lock the market after a pending bet.
  const hasBet     = (mkt, pick) => myBets.some(b => b.matchId===m.id && b.market===mkt && b.pick===pick && b.status==='pending');
  const mktHasBet  = mkt => myBets.some(b => b.matchId===m.id && b.market===mkt && b.status==='pending');
  const t = c => WC.team(c);

  const mkOdd = (mkt, pick, v, lbl, extraLock) => {
    const isOn    = hasBet(mkt, pick);
    const isLocked = locked || extraLock || (mktHasBet(mkt) && !isOn);
    return (
      <Odd k={lbl} v={v} on={isOn} locked={isLocked}
        onClick={() => openBet({ matchId:m.id, market:mkt, pick, odds:v, line: mkt==='ou' ? m.ou.line : m.ah.line })} />
    );
  };

  return (
    <div className="mkt">
      <div className="market-card">
        <div className="mkt-lbl">Asian Handicap</div>
        <div className="mkt-3col">
          {mkOdd('ah','home', m.ah.home, t(m.home).code, false)}
          <div className="mkt-line-pill">
            <div className="mkt-line-val">{WC.fmtLine(m.ah.line)}</div>
            <div className="mkt-line-sub">{t(m.home).code}</div>
          </div>
          {mkOdd('ah','away', m.ah.away, t(m.away).code, false)}
        </div>
        <PopularityBar
          leftLabel={t(m.home).code}
          rightLabel={t(m.away).code}
          left={popularity?.ah?.home}
          right={popularity?.ah?.away}
        />
      </div>

      <div className="market-card">
        <div className="mkt-lbl">Over / Under</div>
        <div className="mkt-3col">
          {mkOdd('ou','over',  m.ou.over,  'Over',  false)}
          <div className="mkt-line-pill">
            <div className="mkt-line-val">{m.ou.line}</div>
            <div className="mkt-line-sub">GOALS</div>
          </div>
          {mkOdd('ou','under', m.ou.under, 'Under', false)}
        </div>
        <PopularityBar
          leftLabel="Over"
          rightLabel="Under"
          left={popularity?.ou?.over}
          right={popularity?.ou?.under}
        />
      </div>
    </div>
  );
}

/* ── Match card ─────────────────────────────────────────── */
function MatchCard({ m, result, myBets, openBet, popularity }) {
  const t = c => WC.team(c);
  const settled = !!result;
  const bettingLocked = settled || !m.bettingOpen || !m.canBet;
  return (
    <div className="mcard">
      <div className="mcard-top">
        <span className="mtag">{m.group}</span>
        {settled
          ? <span className="settled-tag"><Ic.check style={{width:13,height:13}}/> Full Time</span>
          : !m.bettingOpen
            ? <span className="settled-tag" style={{color:'var(--hot)'}}>🔒 Betting Closed</span>
            : <span className="mtime">{WC.formatTime(m.time)}</span>}
      </div>
      <div className="mteams">
        <div className="mteam home"><FlagBadge code={m.home} size={40}/><span className="nm">{t(m.home).name}</span></div>
        {settled
          ? <span className="score-pill">{result.homeGoals} &ndash; {result.awayGoals}</span>
          : <span className="vs">VS</span>}
        <div className="mteam away"><FlagBadge code={m.away} size={40}/><span className="nm">{t(m.away).name}</span></div>
      </div>
      <MarketOdds m={m} myBets={myBets} openBet={openBet} locked={bettingLocked} popularity={popularity} />
    </div>
  );
}

/* ── Matches screen ─────────────────────────────────────── */
function MatchesScreen({ results, myBets, openBet, popularity }) {
  const open = WC.MATCHES.filter(m => !results[m.id] && m.bettingOpen && m.canBet);
  return (
    <div className="pad pad-b">
      <div className="sec-title">Matchday 1 <small>{open.length} fixtures open</small></div>
      {open.map(m => (
        <MatchCard key={m.id} m={m} result={null} myBets={myBets} openBet={openBet} popularity={popularity[m.id]}/>
      ))}
      {open.length === 0 && (
        <div className="empty">
          <div className="em-ic"><Ic.ball style={{width:30,height:30}}/></div>
          <h3>No open matches</h3>
          <p>Check back when betting opens.</p>
        </div>
      )}
    </div>
  );
}

/* ── My Bets ────────────────────────────────────────────── */
const OUTCOME = {
  won:      { t:'WON',       cls:'up'   },
  halfwon:  { t:'HALF WON',  cls:'up'   },
  push:     { t:'PUSH',      cls:'flat' },
  halflost: { t:'HALF LOST', cls:'down' },
  lost:     { t:'LOST',      cls:'down' },
};

function BetRow({ b, onCancel }) {
  const m       = WC.match(b.matchId);
  const settled = b.status==='settled';
  const oc      = settled ? OUTCOME[b.outcome] : null;
  const net     = settled ? b.payout-b.stake : 0;
  const canCancel = !settled && m?.canBet;
  return (
    <div className="slip-item">
      <div className="slip-head">
        {b.market==='ou'
          ? <OUBadge pick={b.pick} size={30}/>
          : <FlagBadge code={b.pick==='away' ? m.away : m.home} size={30}/>}
        <div style={{minWidth:0}}>
          <div className="slip-pick">{pickLabel(b)}</div>
          <div className="slip-meta">{matchLabel(b)}{settled&&b.score ? `  ·  FT ${b.score}` : ''}</div>
          {m && (
            <div className="slip-time">
              {WC.formatTime(m.time)}
            </div>
          )}
        </div>
        <div style={{marginLeft:'auto',textAlign:'right'}}>
          {settled
            ? <div className="lb-pts">
                <div className={'p '+oc.cls} style={{fontSize:11}}>{oc.t}</div>
                <div style={{fontFamily:'var(--disp)',fontWeight:800,fontSize:18}} className={net>0?'up':net<0?'down':'flat'}>
                  {net>0?'+':''}{pts(net)}
                </div>
              </div>
            : <span className="mtag" style={{color:'var(--gold)',background:'#FFF6DC'}}>PENDING</span>}
        </div>
      </div>
      <div className="to-win" style={{marginTop:0,display:'flex',gap:14}}>
        <span>Stake <b style={{color:'var(--ink-2)'}}>{pts(b.stake)}</b></span>
        <span>Odds  <b style={{color:'var(--ink-2)'}}>{WC.fmtOdds(b.odds)}</b></span>
        <span>{settled?'Returned':'To return'} <b style={{color:settled?(b.payout>0?'var(--lime)':'var(--muted)'):'var(--lime)'}}>
          {pts(settled ? b.payout : b.stake*b.odds)}
        </b></span>
      </div>
      {canCancel && (
        <div className="bet-actions">
          <button className="btn btn-danger cancel-bet-btn" onClick={() => onCancel(b)}>
            Cancel bet
          </button>
        </div>
      )}
    </div>
  );
}

function MyBetsScreen({ bets, playerName, onCancelBet }) {
  const mine    = bets.filter(b => b.player===playerName).sort((a,b) => b.placedAt-a.placedAt);
  const pending = mine.filter(b => b.status==='pending');
  const settled = mine.filter(b => b.status==='settled');
  const atRisk  = pending.reduce((a,b) => a+b.stake, 0);
  const net     = settled.reduce((a,b) => a+b.payout-b.stake, 0);
  if (mine.length===0) return (
    <div className="pad pad-b">
      <div className="sec-title">My Bets</div>
      <div className="empty">
        <div className="em-ic"><Ic.ticket style={{width:30,height:30}}/></div>
        <h3>No bets yet</h3>
        <p>Tap any odds on the Matches screen<br/>to place a bet instantly.</p>
      </div>
    </div>
  );
  return (
    <div className="pad pad-b">
      <div className="sec-title">My Bets <small>{mine.length} total</small></div>
      <div style={{display:'flex',gap:10,marginBottom:14}}>
        <div style={{flex:1,background:'var(--card)',borderRadius:14,boxShadow:'var(--sh-card)',padding:'11px 13px'}}>
          <div style={{fontSize:10.5,color:'var(--muted)',fontWeight:700,textTransform:'uppercase',letterSpacing:'.06em'}}>At risk</div>
          <div style={{fontFamily:'var(--disp)',fontWeight:800,fontSize:22}}>{pts(atRisk)}</div>
        </div>
        <div style={{flex:1,background:'var(--card)',borderRadius:14,boxShadow:'var(--sh-card)',padding:'11px 13px'}}>
          <div style={{fontSize:10.5,color:'var(--muted)',fontWeight:700,textTransform:'uppercase',letterSpacing:'.06em'}}>Settled P/L</div>
          <div className={net>0?'up':net<0?'down':'flat'} style={{fontFamily:'var(--disp)',fontWeight:800,fontSize:22}}>{net>0?'+':''}{pts(net)}</div>
        </div>
      </div>
      {pending.length>0 && <div className="mkt-lbl" style={{margin:'2px 2px 10px'}}>Open &middot; {pending.length}</div>}
      {pending.map(b => <BetRow key={b.id} b={b} onCancel={onCancelBet}/>)}
      {settled.length>0 && <div className="mkt-lbl" style={{margin:'16px 2px 10px'}}>Settled &middot; {settled.length}</div>}
      {settled.map(b => <BetRow key={b.id} b={b} onCancel={onCancelBet}/>)}
    </div>
  );
}

/* ── Leaderboard ────────────────────────────────────────── */
const MEDAL = [
  'linear-gradient(135deg,#FFD24A,#F5A300)',
  'linear-gradient(135deg,#D3DAE6,#9AA6BC)',
  'linear-gradient(135deg,#E5A36B,#C2773E)',
];

function OpenBetPreview({ b }) {
  const m = WC.match(b.matchId);
  if (!m) return null;
  return (
    <div className="public-bet">
      <div className="public-bet-main">
        <div className="public-bet-pick">{pickLabel(b)}</div>
        <div className="public-bet-match">{matchLabel(b)}</div>
        <div className="public-bet-time">{WC.formatTime(m.time)}</div>
      </div>
      <div className="public-bet-numbers">
        <strong>{pts(b.stake)}</strong>
        <span>@ {WC.fmtOdds(b.odds)}</span>
      </div>
    </div>
  );
}

function PlayerOpenBetsModal({ detail, onClose }) {
  if (!detail) return null;
  const { row, bets, loading } = detail;
  return (
    <div className="rank-modal-bg" onClick={e => e.target===e.currentTarget && onClose()}>
      <div className="rank-sheet">
        <div className="rank-sheet-head">
          <div>
            <div className="rank-sheet-kicker">Open bets</div>
            <h3>{row.name}</h3>
          </div>
          <button className="x-btn" onClick={onClose}><Ic.x style={{width:15,height:15}}/></button>
        </div>
        <div className="rank-sheet-summary">
          <span><b className="wdl-w">{row.wins} W</b><b className="wdl-d">{row.draws} D</b><b className="wdl-l">{row.losses} L</b></span>
          <strong>{pts(row.pending)} at risk</strong>
        </div>
        {loading ? (
          <div className="rank-bets-empty">Loading bets...</div>
        ) : bets.length ? (
          <div className="public-bet-list">{bets.map(b => <OpenBetPreview key={b.id} b={b}/>)}</div>
        ) : (
          <div className="rank-bets-empty">No open bets</div>
        )}
      </div>
    </div>
  );
}

function LeaderboardScreen({ rows, playerName }) {
  const [detail, setDetail] = useState(null);
  const lastUpdatedAt = rows[0]?.lastUpdatedAt || 0;

  const showOpenBets = async row => {
    setDetail({ row, bets:[], loading:true });
    const bets = await E.pendingBets(row.name);
    setDetail(current => current?.row.name===row.name ? { row, bets, loading:false } : current);
  };

  if (!rows.length) return (
    <div className="pad pad-b">
      <div className="sec-title">Leaderboard</div>
      <div className="empty">
        <div className="em-ic"><Ic.trophy style={{width:30,height:30}}/></div>
        <h3>No players yet</h3>
        <p>Be the first to enter!</p>
      </div>
    </div>
  );
  return (
    <div className="pad pad-b">
      <div className="sec-title">Leaderboard <small>{rows.length} player{rows.length>1?'s':''}</small></div>
      <div className="lb-updated">Last update: {fmtUpdateTime(lastUpdatedAt)}</div>
      {rows.map((r,i) => {
        const me = r.name===playerName;
        const cls = r.profit>0?'up':r.profit<0?'down':'flat';
        return (
          <button className="lb-row lb-click" key={r.name} onClick={()=>showOpenBets(r)}
            style={me?{boxShadow:'0 0 0 2px var(--violet), var(--sh-card)'}:null}>
            {i<3 ? <span className="medal" style={{background:MEDAL[i]}}>{i+1}</span>
                 : <span className="rank">{i+1}</span>}
            <div className="lb-main">
              <div className="lb-name" style={{display:'flex',alignItems:'center',gap:7}}>
                {r.name} {me && <span className="me-tag">You</span>}
              </div>
              <div className="lb-sub">{r.pending>0 ? `${pts(r.pending)} in open bets` : 'No open bets'}</div>
              <div className="wdl">
                <span className="wdl-w"><b>{r.wins}</b> W</span>
                <span className="wdl-d"><b>{r.draws}</b> D</span>
                <span className="wdl-l"><b>{r.losses}</b> L</span>
              </div>
            </div>
            <div className="lb-pts">
              <div className="n">{pts(r.net)}</div>
              <div className={'p '+cls}>{r.profit>0?'+':''}{pts(r.profit)}</div>
            </div>
          </button>
        );
      })}
      <PlayerOpenBetsModal detail={detail} onClose={()=>setDetail(null)}/>
    </div>
  );
}

function buildPopularity(rows) {
  return (rows || []).reduce((acc, r) => {
    acc[r.matchId] ||= {};
    acc[r.matchId][r.market] ||= {};
    acc[r.matchId][r.market][r.pick] = { count:r.count, amount:r.amount };
    return acc;
  }, {});
}

/* ── Settle Results ─────────────────────────────────────── */
function ScoreBox({ value, onChange }) {
  return (
    <input className="score-in" type="number" inputMode="numeric" min="0" placeholder="0"
      value={value} onChange={e => onChange(e.target.value.replace(/[^0-9]/g,'').slice(0,2))}/>
  );
}

function ResultRow({ m, result, onSettle, onReopen, pendingCount }) {
  const [hg, setHg] = useState(result ? String(result.homeGoals) : '');
  const [ag, setAg] = useState(result ? String(result.awayGoals) : '');
  const t = c => WC.team(c);
  const settled = !!result;
  return (
    <div className="res-card">
      <div className="mcard-top" style={{padding:'0 0 9px',border:'none'}}>
        <span className="mtag">{m.group}</span>
        <span className="mtime">{WC.formatTime(m.time)}</span>
        <span className="mvenue">{settled?`${pendingCount} bets settled`:`${pendingCount} open bet${pendingCount===1?'':'s'}`}</span>
      </div>
      <div className="res-teams">
        <div className="mteam home" style={{justifyContent:'flex-end'}}>
          <span className="nm">{t(m.home).name}</span><FlagBadge code={m.home} size={32}/>
        </div>
        <ScoreBox value={hg} onChange={setHg}/>
        <span className="res-dash">:</span>
        <ScoreBox value={ag} onChange={setAg}/>
        <div className="mteam away" style={{flexDirection:'row',justifyContent:'flex-start'}}>
          <FlagBadge code={m.away} size={32}/><span className="nm">{t(m.away).name}</span>
        </div>
      </div>
      {settled
        ? <button className="btn btn-ghost btn-block btn-sm" onClick={()=>onReopen(m.id)}>Re-open &amp; re-enter score</button>
        : <button className="btn btn-dark  btn-block btn-sm" onClick={()=>onSettle(m.id,hg,ag)}>Settle this match</button>}
    </div>
  );
}

function ResultsScreen({ bets, results, onSettle, onReopen, onBack }) {
  const countBets = id => bets.filter(b =>
    b.matchId===id && (results[id] ? b.status==='settled' : b.status==='pending')).length;
  const open = WC.MATCHES.filter(m => !results[m.id]);
  const done = WC.MATCHES.filter(m =>  results[m.id]);
  return (
    <div className="pad pad-b">
      <div style={{display:'flex',alignItems:'center',gap:10,margin:'2px 0 6px'}}>
        <button className="x-btn" style={{width:34,height:34}} onClick={onBack}>
          <Ic.out style={{width:18,height:18,transform:'scaleX(-1)'}}/>
        </button>
        <div className="sec-title" style={{margin:0,flex:1}}>Settle Results</div>
      </div>
      <p style={{fontSize:12.5,color:'var(--muted)',fontWeight:500,margin:'0 2px 16px',lineHeight:1.5}}>
        Enter each match&rsquo;s real final score to grade all open bets instantly.
      </p>
      {open.map(m => <ResultRow key={m.id} m={m} result={null} pendingCount={countBets(m.id)} onSettle={onSettle} onReopen={onReopen}/>)}
      {done.length>0 && (
        <>
          <div className="mkt-lbl" style={{margin:'14px 2px 10px'}}>Settled &middot; {done.length}</div>
          {done.map(m => <ResultRow key={m.id} m={m} result={results[m.id]} pendingCount={countBets(m.id)} onSettle={onSettle} onReopen={onReopen}/>)}
        </>
      )}
    </div>
  );
}

/* ── Root App ───────────────────────────────────────────── */
function App() {
  const [gameState,  setGameState]  = useState(null);
  const [lb,         setLb]         = useState([]);
  const [popularity, setPopularity] = useState({});
  const [loaded,     setLoaded]     = useState(false);
  const [tab,        setTab]        = useState('matches');
  const [quickBet,   setQuickBet]   = useState(null); // { matchId, market, pick, odds, line }
  const [toastNode,  toast]         = useToasts();
  const scrollRef = useRef(null);

  const refresh = useCallback(async () => {
    const [s, pop] = await Promise.all([E.fetchState(), E.betPopularity()]);
    setGameState(s);
    setPopularity(buildPopularity(pop));
    return s;
  }, []);

  useEffect(() => {
    (async () => {
      const [matches, state, pop, ranking] = await Promise.all([
        E.getMatches(), E.fetchState(), E.betPopularity(), E.leaderboard(),
      ]);
      WC.MATCHES = matches;
      setGameState(state);
      setPopularity(buildPopularity(pop));
      setLb(ranking);
      setLoaded(true);
    })();
  }, []);

  useEffect(() => { if (scrollRef.current) scrollRef.current.scrollTop = 0; }, [tab]);
  useEffect(() => { if (tab==='ranks') E.leaderboard().then(setLb); }, [tab]);

  if (!loaded) return (
    <div className="stage">
      <div className="phone" style={{display:'flex',alignItems:'center',justifyContent:'center'}}>
        <span style={{color:'var(--muted)',fontFamily:'var(--disp)',fontSize:22}}>Loading…</span>
      </div>
    </div>
  );

  if (!gameState) return (
    <div className="stage">
      <div className="phone">
        <Onboarding leaderboard={lb} onJoin={async (name, password) => {
          const res = await E.joinOrSelect(name, password);
          if (!res.ok) { toast(res.msg || 'Login failed', 'bad'); return; }
          const [state, pop] = await Promise.all([E.fetchState(), E.betPopularity()]);
          setGameState(state);
          setPopularity(buildPopularity(pop));
          setTab('matches');
        }}/>
      </div>
    </div>
  );

  const { player, bets, results } = gameState;
  const myBets = bets.filter(b => b.player===player.name);

  /* ── Open quick-bet modal after validating duplicate limits ── */
  const openBet = sel => {
    // One pending bet per match market.
    const dup = myBets.find(b =>
      b.matchId===sel.matchId && b.market===sel.market && b.status==='pending');
    if (dup) {
      toast('You already have a pending bet on this market', 'bad');
      return;
    }
    setQuickBet(sel);
  };

  /* ── Settle ── */
  const settle = async (id, hg, ag) => {
    const res = await E.settleMatch(id, parseInt(hg,10), parseInt(ag,10));
    if (!res.ok) { toast(res.msg||'Error','bad'); return; }
    const m = WC.match(id);
    const d = res.netDelta ?? 0;
    const newState = await refresh();
    if (tab==='ranks') E.leaderboard().then(setLb);
    if (d>0)      toast(`${WC.team(m.home).code} ${hg}-${ag} ${WC.team(m.away).code} · you won +${pts(d)}`,'good');
    else if (d<0) toast(`${WC.team(m.home).code} ${hg}-${ag} ${WC.team(m.away).code} · you lost ${pts(Math.abs(d))}`,'bad');
    else          toast(`${WC.team(m.home).code} ${hg}-${ag} ${WC.team(m.away).code} settled`,'');
  };
  const reopen = async id => {
    await E.reopenMatch(id); await refresh();
    toast('Match re-opened','');
  };
  const cancelBet = async bet => {
    const res = await E.cancelBet(bet.id);
    if (!res.ok) { toast(res.msg || 'Unable to cancel bet', 'bad'); return; }
    await refresh();
    toast(`Bet cancelled · ${pts(bet.stake)} pts returned`, 'good');
  };

  const myPending  = myBets.filter(b => b.status==='pending').length;
  const rank       = lb.findIndex(r => r.name===player.name)+1;
  const totalP     = lb.length;

  let body;
  if      (tab==='matches') body = <MatchesScreen results={results} myBets={myBets} openBet={openBet} popularity={popularity}/>;
  else if (tab==='bets')    body = <MyBetsScreen  bets={bets} playerName={player.name} onCancelBet={cancelBet}/>;
  else if (tab==='ranks')   body = <LeaderboardScreen rows={lb} playerName={player.name}/>;
  else if (tab==='results') body = <ResultsScreen bets={bets} results={results} onSettle={settle} onReopen={reopen} onBack={()=>setTab('matches')}/>;

  return (
    <div className="stage">
      <div className="phone">
        {tab!=='results' && (
          <Header player={player} big={tab==='matches'}
            subtitle={rank>0 ? `Rank #${rank} of ${totalP} · ${myPending} open bet${myPending===1?'':'s'}` : `${myPending} open bet${myPending===1?'':'s'}`}
            onLogout={() => { E.logout(); setGameState(null); setQuickBet(null); }}/>
        )}
        <div className="scroll" ref={scrollRef}>{body}</div>
        {tab!=='results' && <Nav tab={tab} setTab={setTab} pendingCount={myPending}/>}

        {/* Quick bet modal */}
        {quickBet && (
          <QuickBetModal
            sel={quickBet}
            balance={player.balance}
            onClose={() => setQuickBet(null)}
            onPlaced={async () => { setQuickBet(null); await refresh(); }}
            toast={toast}
          />
        )}

        {toastNode}
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
