/* components.jsx — shared React components. Exports to window. */
const { useState, useEffect, useRef, useCallback, useMemo } = React;

/* ---------- buttons / pills ---------- */
function Btn({ variant = 'gold', size, block, children, className = '', ...p }) {
  const cls = ['btn', `btn--${variant}`, size && `btn--${size}`, block && 'btn--block', className].filter(Boolean).join(' ');
  return <button className={cls} {...p}>{children}</button>;
}
function Pill({ tone, children, className = '' }) {
  return <span className={`pill ${tone ? 'pill--' + tone : ''} ${className}`}>{children}</span>;
}
function AccuracyBadge({ pct, size = 'md' }) {
  const level = window.WCLogic.accuracyClass(pct);
  return (
    <span className="acc-badge tnum" data-level={level} style={{ fontSize: size === 'lg' ? 22 : 14 }}>
      <b>{pct}%</b>
    </span>
  );
}

/* ============================================================
   Match tile
   ============================================================ */
function Stepper({ value, onChange }) {
  const v = Number.isFinite(value) ? value : 0;
  return (
    <div className="stepper">
      <button type="button" onClick={() => onChange(Math.max(0, v - 1))} aria-label="minus">–</button>
      <input value={Number.isFinite(value) ? value : ''} inputMode="numeric"
        onChange={(e) => { const n = parseInt(e.target.value.replace(/\D/g, ''), 10); onChange(Number.isFinite(n) ? Math.min(n, 19) : 0); }} />
      <button type="button" onClick={() => onChange(v + 1)} aria-label="plus">+</button>
    </div>
  );
}

function MatchTile({ match, result, onSet, locked, actual }) {
  const home = window.WC.team(match.home), away = window.WC.team(match.away);
  const o = result && result.o;
  const setOutcome = (val) => {
    onSet(match.id, { o: val });
    window.bwcpTrack?.('bwcp_prediction_made', {
      group: match.group, match_id: match.id, result: val,
    });
  };
  const setScore = (side, n) => {
    const next = { ...(result || {}), [side]: n };
    if (Number.isFinite(next.hs) && Number.isFinite(next.as))
      next.o = next.hs > next.as ? 'H' : next.hs < next.as ? 'A' : 'D';
    onSet(match.id, next);
  };

  const sup = window.bwcpSupported;
  const SupportStar = ({ code }) => sup?.has(code)
    ? <span className="team-supported" title="Your team">★</span>
    : null;

  if (locked && actual) {
    const correct = result && result.o ? result.o === actual.o : null;
    const predLabel = !result || !result.o ? 'No pick' :
      result.o === 'H' ? home.name + ' win' : result.o === 'A' ? away.name + ' win' : 'Draw';
    return (
      <div className="tile" data-locked="1">
        <div className="tile__head">
          <span><b style={{ color: 'var(--ink-mut)' }}>{match.group}{match.md}</b> · {match.date}</span>
          <span className="row" style={{ gap: 4 }}><IconLock size={11} /> FT</span>
        </div>
        <div className="tile__row">
          <div className="tile__side"><Flag code={match.home} /><span className="tile__nm">{home.name}</span><SupportStar code={match.home} /></div>
          <div className="tile__final tnum">
            {actual.hs}<span style={{ opacity: .4, margin: '0 2px' }}>:</span>{actual.as}
          </div>
          <div className="tile__side tile__side--away"><SupportStar code={match.away} /><Flag code={match.away} /><span className="tile__nm">{away.name}</span></div>
        </div>
        <div className="tile__verline">
          <span className="tile__pick">Your pick: <b style={{ color: 'var(--ink-soft)' }}>{predLabel}</b></span>
          {correct !== null && <Verdict ok={correct} size={20} />}
        </div>
      </div>
    );
  }

  return (
    <div className="tile">
      <div className="tile__head">
        <span><b style={{ color: 'var(--ink-mut)' }}>{match.group}{match.md}</b> · {match.date}</span>
        {o && <span style={{ color: 'var(--gold)' }}>predicted</span>}
      </div>
      <div className="tile__row">
        <div className="tile__side"><Flag code={match.home} /><span className="tile__nm">{home.name}</span><SupportStar code={match.home} /></div>
        <span className="tile__vs">v</span>
        <div className="tile__side tile__side--away"><SupportStar code={match.away} /><Flag code={match.away} /><span className="tile__nm">{away.name}</span></div>
      </div>
      <div className="seg">
        <button className="seg__btn" data-kind="home" data-on={o === 'H' ? 1 : 0} onClick={() => setOutcome('H')}>{home.code}</button>
        <button className="seg__btn" data-kind="draw" data-on={o === 'D' ? 1 : 0} onClick={() => setOutcome('D')}>X</button>
        <button className="seg__btn" data-kind="away" data-on={o === 'A' ? 1 : 0} onClick={() => setOutcome('A')}>{away.code}</button>
      </div>
      <div className="score" data-show={o ? 1 : 0}>
        <Stepper value={result && result.hs} onChange={(n) => setScore('hs', n)} />
        <span className="score__dash">–</span>
        <Stepper value={result && result.as} onChange={(n) => setScore('as', n)} />
      </div>
    </div>
  );
}

/* ============================================================
   Group table
   ============================================================ */
function GroupTable({ rows, compact }) {
  return (
    <table className="gtable">
      <thead>
        <tr>
          <th></th><th className="col-team">Team</th>
          <th>P</th>{!compact && <th>W</th>}{!compact && <th>D</th>}{!compact && <th>L</th>}
          <th>GD</th><th>Pts</th>
        </tr>
      </thead>
      <tbody>
        {rows.map((r, i) => (
          <tr key={r.code} data-qual={i < 2 ? i + 1 : undefined}>
            <td className="pos">{i + 1}</td>
            <td>
              <span className="teamcell"><Flag code={r.code} size={18} /><b>{window.WC.team(r.code).name}</b></span>
            </td>
            <td className="num">{r.P}</td>
            {!compact && <td className="num">{r.W}</td>}
            {!compact && <td className="num">{r.D}</td>}
            {!compact && <td className="num">{r.L}</td>}
            <td className="num">{r.GD > 0 ? '+' + r.GD : r.GD}</td>
            <td className="pts tnum">{r.Pts}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

/* ============================================================
   Group card (matches + live standings)
   ============================================================ */
function GroupCard({ group, results, onSet }) {
  const meta = window.WC.groupMeta[group];
  const fixtures = window.WC.fixtures.filter((f) => f.group === group);
  const rows = window.WCLogic.standingsFor(group, results);
  const done = fixtures.filter((f) => results[f.id] && results[f.id].o).length;
  return (
    <div className="gcard">
      <div className="gcard__head">
        <div className="gcard__title">
          <span className="gcard__letter">{group}</span>
          <div>
            <div style={{ fontWeight: 800, fontSize: 'var(--fs-sm)' }}>Group {group}</div>
            <div className="gcard__sub">{meta.host}</div>
          </div>
        </div>
        <Pill tone={done === 6 ? 'green' : undefined}>{done}/6</Pill>
      </div>
      <div className="gcard__body">
        {fixtures.map((f) => (
          <MatchTile key={f.id} match={f} result={results[f.id]} onSet={onSet} />
        ))}
        <div className="gcard__tablewrap">
          <div className="gcard__tabletitle"><span>Predicted standings</span><span style={{ color: 'var(--gold)' }}>Top 2 ⟶ knockouts</span></div>
          <GroupTable rows={rows} />
        </div>
      </div>
    </div>
  );
}

/* ============================================================
   Bracket node
   ============================================================ */
function BracketNode({ match, pickedWinner, onPick, locked, actualWinner, header }) {
  const slot = (code, label, isB) => {
    const t = code ? window.WC.team(code) : null;
    const win = pickedWinner && code && pickedWinner === code ? 1 : 0;
    let correct;
    if (locked && win) correct = actualWinner ? (pickedWinner === actualWinner ? 1 : 0) : undefined;
    return (
      <div className="bnode__slot" data-win={win} data-correct={correct}
        onClick={() => {
          if (locked || !code || !onPick) return;
          onPick(match.key, code);
          const round = match.key.split('-')[0];
          window.bwcpTrack?.(round === 'F' ? 'bwcp_champion_picked' : 'bwcp_ko_pick_made', {
            round, match_key: match.key, team: code,
          });
        }}>
        {t ? <Flag code={code} size={18} /> : <span className="flag flag--tbd" style={{ fontSize: 18 }}>·</span>}
        {t ? <span className="team__name">{t.name}</span> : <span className="tbd">{label}</span>}
        {t && window.bwcpSupported?.has(code) && <span className="team-supported" style={{ marginLeft: 'auto', flexShrink: 0 }}>★</span>}
        {locked && win === 1 && correct !== undefined && <span style={{ marginLeft: !window.bwcpSupported?.has(code) ? 'auto' : 0 }}><Verdict ok={correct === 1} size={16} /></span>}
      </div>
    );
  };
  return (
    <div className="bnode">
      {header && <div className="bnode__hd"><span>{header}</span></div>}
      {slot(match.aCode, match.aLabel)}
      {slot(match.bCode, match.bLabel, true)}
    </div>
  );
}

/* ============================================================
   Confetti — rank #1 celebration burst
   ============================================================ */
const CONFETTI_COLORS = ['var(--gold)', 'var(--gold-bright)', 'var(--pitch)', 'var(--win)', '#fff'];
function Confetti({ onDone }) {
  const pieces = useMemo(() => Array.from({ length: 50 }, (_, i) => ({
    id: i,
    left: Math.random() * 100,
    delay: Math.random() * 0.35,
    duration: 2.4 + Math.random() * 1.6,
    color: CONFETTI_COLORS[i % CONFETTI_COLORS.length],
    rot: Math.round(Math.random() * 720 - 360),
    drift: Math.round((Math.random() - 0.5) * 160),
    w: 6 + Math.round(Math.random() * 6),
  })), []);

  useEffect(() => {
    const t = setTimeout(() => onDone?.(), 4200);
    return () => clearTimeout(t);
  }, []);

  return (
    <div className="confetti" aria-hidden="true">
      {pieces.map(p => (
        <span key={p.id} className="confetti__piece" style={{
          left: p.left + '%',
          background: p.color,
          width: p.w, height: p.w * 0.4,
          animationDelay: p.delay + 's',
          animationDuration: p.duration + 's',
          '--drift': p.drift + 'px',
          '--rot': p.rot + 'deg',
        }} />
      ))}
    </div>
  );
}

Object.assign(window, { Btn, Pill, AccuracyBadge, Stepper, MatchTile, GroupTable, GroupCard, BracketNode, Confetti });
