/* =====================================================
   Betting Tracker — Bets page + full add/edit form
   The complete schema from the brief lives in the form,
   grouped into sections, with live edge / EV / implied.
   ===================================================== */

const uid = () => "b" + Math.random().toString(36).slice(2, 8);

// page-number list with ellipses, e.g. 1 2 3 … 10
function pageRange(cur, total) {
  const out = []; let last = 0;
  for (let i = 1; i <= total; i++) {
    if (i === 1 || i === total || (i >= cur - 1 && i <= cur + 1)) {
      if (last && i - last > 1) out.push("\u2026");
      out.push(i); last = i;
    }
  }
  return out;
}

function blankBet(state) {
  const bks = TRK.bookOptions(state);
  const sps = state.settings.sports || TRK.SPORTS;
  return {
    id: uid(), date: TRK.today(), time: "", book: bks[0] || "Pinnacle", sport: sps[0] || "Soccer", league: "",
    teamA: "", teamB: "", map: "", source: "own", tipster: (state.models[0] ? state.models[0].name : "Me"), market: "Moneyline", line: "",
    side: "", player: "", position: "", minutes: "", projection: "", actual: "",
    live: false, stake: state.settings.flatStake || state.settings.unitSize, odds: 2.0,
    result: "pending", closingOdds: "", modelProb: "", tags: ["Normal"], notes: "",
    returned: "", isParlay: false, legs: [],
    bankrollId: state.bankrolls[0] ? state.bankrolls[0].id : "bk1"
  };
}

/* ---------- section header (icon + title, one per card) ---------- */
function SecHead({ icon, children }) {
  return (
    <div className="trk-form__sechead">
      <span className="trk-form__secic"><Icon name={icon} size={14} /></span>
      <span className="trk-form__sectitle">{children}</span>
    </div>
  );
}

/* ---------- the drawer form ---------- */
function BetForm({ initial, onSave, onDelete, onDuplicate, onCancel, isNew }) {
  const { state, t } = useTracker();
  const [b, setB] = useState(initial);
  const set = (k, v) => setB((p) => ({ ...p, [k]: v }));
  const cur = state.settings.currency;

  const num = (v) => (v === "" || v == null ? null : parseFloat(v));
  const oddsN = num(b.odds), stakeN = num(b.stake);
  const closeN = num(b.closingOdds), mp = num(b.modelProb);
  // parlay: effective odds are the product of leg odds
  const combined = b.isParlay ? TRK.parlayOdds(b.legs) : null;
  const effOdds = b.isParlay ? combined : oddsN;
  const impl = effOdds > 1 ? 100 / effOdds : null;
  const preview = { ...b, odds: effOdds, stake: stakeN, closingOdds: closeN, modelProb: mp != null ? mp / 100 : null };
  const edge = TRK.betEdge(preview);
  const ev = TRK.betEV(preview);
  const clv = TRK.betCLV(preview);

  // leg editing helpers
  const setLeg = (i, k, v) => set("legs", b.legs.map((l, j) => (j === i ? { ...l, [k]: v } : l)));
  const addLeg = () => set("legs", [...(b.legs || []), { event: "", market: "", sel: "", odds: "" }]);
  const rmLeg = (i) => set("legs", b.legs.filter((_, j) => j !== i));

  // Kelly readout vs current bankroll
  const bankNow = TRK.bankrollBalance(state);
  const fullK = mp != null && effOdds > 1 ? TRKQ.kellyPct({ modelProb: mp / 100, odds: effOdds }) : null;
  const kFrac = state.settings.kellyFraction || 1;
  const sugg = fullK != null && bankNow > 0 ? bankNow * (fullK / 100) * kFrac : null;
  const actPct = stakeN && bankNow > 0 ? (stakeN / bankNow) * 100 : null;
  const kDelta = fullK != null && actPct != null ? actPct - fullK * kFrac : null;

  const toggleTag = (tag) => set("tags", b.tags.includes(tag) ? b.tags.filter((x) => x !== tag) : [...b.tags, tag]);

  const commit = () => {
    const legsClean = (b.legs || []).filter((l) => l && (l.sel || l.odds || l.event || l.market)).map((l) => ({ event: l.event || "", market: l.market || "", sel: l.sel || "", odds: parseFloat(l.odds) || 0 }));
    const combinedC = b.isParlay ? TRK.parlayOdds(legsClean) : null;
    const clean = {
      ...b, odds: b.isParlay && combinedC ? combinedC : (oddsN || 0), stake: stakeN || 0,
      closingOdds: closeN, modelProb: mp != null ? mp / 100 : null,
      minutes: num(b.minutes), projection: num(b.projection), actual: num(b.actual),
      returned: num(b.returned), isParlay: !!b.isParlay, legs: legsClean, source: (b.source === "own" || b.source === "tipster") ? b.source : TRK.betSource(b)
    };
    onSave(clean);
  };

  return (
    <div className="trk-form">
      {/* Outcome — the field users change most, pulled out and highlighted */}
      <div className="trk-outcome">
        <div className="trk-outcome__lab"><Icon name="target" size={15} /> {t("form.result")}</div>
        <div className="trk-outcome__opts">
          {TRK.RESULTS.map((r) => (
            <button key={r} type="button"
              className={"trk-outcome__b" + (b.result === r ? " is-active is-" + r : "")}
              onClick={() => set("result", r)}>{t("res." + r)}</button>
          ))}
        </div>
        {b.result === "cashout" && (
          <Field label={t("form.returned") + " (" + cur + ")"} hint={t("form.returnedHint")}>
            <Input type="number" step="1" value={b.returned == null ? "" : b.returned} placeholder={String(stakeN || "")} onChange={(e) => set("returned", e.target.value)} />
          </Field>
        )}
      </div>

      {/* Match */}
      <div className="trk-form__sec">
        <SecHead icon="file">{t("form.sec.match")}</SecHead>
        {/* the matchup — who the bet is on, pulled out so it reads at a glance */}
        <div className="trk-matchup">
          <label className="trk-matchup__side">
            <span className="trk-matchup__lab">{t("form.teamA")}</span>
            <Input value={b.teamA} placeholder="Arsenal" onChange={(e) => set("teamA", e.target.value)} />
          </label>
          <span className="trk-matchup__vs">vs</span>
          <label className="trk-matchup__side">
            <span className="trk-matchup__lab">{t("form.teamB")}</span>
            <Input value={b.teamB} placeholder="Chelsea" onChange={(e) => set("teamB", e.target.value)} />
          </label>
        </div>
        <div className="trk-form__grid">
          <Field label={t("form.date")}><Input type="date" value={b.date} onChange={(e) => set("date", e.target.value)} /></Field>
          <Field label={t("form.time")}><Input type="time" value={b.time || ""} onChange={(e) => set("time", e.target.value)} /></Field>
          <Field label={t("form.book")}><Select value={b.book} onChange={(v) => set("book", v)} options={TRK.bookOptions(state)} /></Field>
          <Field label={t("form.sport")}><Select value={b.sport} onChange={(v) => set("sport", v)} options={state.settings.sports || TRK.SPORTS} /></Field>
          <Field label={t("form.league")}><Input value={b.league} placeholder="Premier League" onChange={(e) => set("league", e.target.value)} /></Field>
          <Field label={t("form.map")}><Input value={b.map} placeholder="Map 1 / 1st half" onChange={(e) => set("map", e.target.value)} /></Field>
        </div>
        {/* whose pick is this — explicit, drives the analytics “My own vs Tipsters” split */}
        <div className="trk-source">
          <span className="trk-source__lab">{t("form.source")}</span>
          <Segmented size="sm" value={b.source || "own"}
            options={[{ value: "own", label: t("form.source.own") }, { value: "tipster", label: t("form.source.tipster") }]}
            onChange={(v) => set("source", v)} />
          <Field label={b.source === "tipster" ? t("form.tipsterName") : t("form.ownName")}>
            <Select value={b.tipster} onChange={(v) => set("tipster", v)} options={state.models.map((m) => m.name)} />
          </Field>
        </div>
      </div>

      {/* Market & selection */}
      <div className="trk-form__sec">
        <SecHead icon="target">{t("form.sec.market")}</SecHead>
        <div className="trk-form__parlayrow">
          <Segmented size="sm" value={b.isParlay ? "yes" : "no"}
            options={[{ value: "no", label: t("form.single") }, { value: "yes", label: t("form.parlay") }]}
            onChange={(v) => { const on = v === "yes"; set("isParlay", on); if (on && (!b.legs || !b.legs.length)) set("legs", [{ event: (b.teamA || "") + (b.teamB ? " vs " + b.teamB : ""), market: b.market || "", sel: b.side || "", odds: b.odds || "" }, { event: "", market: "", sel: "", odds: "" }]); }} />
          {b.isParlay && <span className="trk-form__parlayhint">{t("form.parlayHint")}</span>}
        </div>
        {b.isParlay ? (
          <div className="trk-legs">
            {(b.legs || []).map((l, i) => (
              <div className="trk-leg" key={i}>
                <div className="trk-leg__top">
                  <span className="trk-leg__n">{t("form.leg")} {i + 1}</span>
                  <button type="button" className="trk-iconbtn trk-iconbtn--sm" onClick={() => rmLeg(i)} aria-label="Remove leg"><Icon name="trash" size={14} /></button>
                </div>
                <div className="trk-leg__grid">
                  <Field label={t("form.legevent")} span><Input value={l.event || ""} placeholder="Arsenal vs Chelsea" onChange={(e) => setLeg(i, "event", e.target.value)} /></Field>
                  <Field label={t("form.legmarket")}><Select value={l.market || ""} onChange={(v) => setLeg(i, "market", v)} options={TRK.marketOptions(state)} placeholder={t("form.legmarket")} /></Field>
                  <Field label={t("form.legsel")}><Input value={l.sel} placeholder="Over 2.5" onChange={(e) => setLeg(i, "sel", e.target.value)} /></Field>
                  <Field label={t("form.odds")}><Input type="number" step="0.01" value={l.odds} placeholder="1.90" onChange={(e) => setLeg(i, "odds", e.target.value)} /></Field>
                </div>
              </div>
            ))}
            <div className="trk-legs__foot">
              <button type="button" className="trk-textlink trk-textlink--sm" onClick={addLeg}><Icon name="plus" size={13} /> {t("form.addleg")}</button>
              <span className="trk-legs__combined">{t("form.combined")}: <b>{combined == null ? "\u2014" : TRK.fmtOdds(combined)}</b></span>
            </div>
          </div>
        ) : null}
        <div className="trk-form__grid">
          <Field label={t("form.market")}><Select value={b.market} onChange={(v) => set("market", v)} options={TRK.marketOptions(state)} /></Field>
          <Field label={t("form.line")}><Input value={b.line} placeholder="-1.5 / 2.5" onChange={(e) => set("line", e.target.value)} /></Field>
          <Field label={t("form.side")} span><Input value={b.side} placeholder="Arsenal / Over 2.5 / Home -1" onChange={(e) => set("side", e.target.value)} /></Field>
          <Field label={t("form.player")}><Input value={b.player} placeholder="Nikola Jokic" onChange={(e) => set("player", e.target.value)} /></Field>
          <Field label={t("form.live")}>
            <div className="trk-form__toggle">
              <Segmented size="sm" value={b.live ? "live" : "pre"}
                options={[{ value: "pre", label: t("seg.pre") }, { value: "live", label: t("seg.live") }]}
                onChange={(v) => set("live", v === "live")} />
            </div>
          </Field>
          {b.player ? (
            <React.Fragment>
              <Field label={t("form.position")}><Input value={b.position || ""} placeholder="C / PG / WR" onChange={(e) => set("position", e.target.value)} /></Field>
              <Field label={t("form.minutes")}><Input type="number" value={b.minutes == null ? "" : b.minutes} placeholder="34" onChange={(e) => set("minutes", e.target.value)} /></Field>
              <Field label={t("form.projection")}><Input type="number" step="0.1" value={b.projection == null ? "" : b.projection} placeholder="28.4" onChange={(e) => set("projection", e.target.value)} /></Field>
              <Field label={t("form.actual")}><Input type="number" step="0.1" value={b.actual == null ? "" : b.actual} placeholder="31" onChange={(e) => set("actual", e.target.value)} /></Field>
            </React.Fragment>
          ) : null}
        </div>
      </div>

      {/* Stake & odds */}
      <div className="trk-form__sec">
        <SecHead icon="wallet">{t("form.sec.stake")}</SecHead>
        <div className="trk-form__grid">
          <Field label={t("form.stake")}><Input type="number" step="1" value={b.stake} onChange={(e) => set("stake", e.target.value)} /></Field>
          <Field label={t("form.odds")}><Input type="number" step="0.01" value={b.isParlay ? (combined == null ? "" : combined) : b.odds} disabled={b.isParlay} onChange={(e) => set("odds", e.target.value)} /></Field>
          <Field label={t("form.bankroll")} span><Select value={b.bankrollId} onChange={(v) => set("bankrollId", v)} options={state.bankrolls.map((w) => ({ value: w.id, label: w.name }))} /></Field>
        </div>
      </div>

      {/* Model & closing */}
      <div className="trk-form__sec">
        <SecHead icon="chart">{t("form.sec.model")}</SecHead>
        <div className="trk-form__grid">
          <Field label={t("form.closing")}><Input type="number" step="0.01" value={b.closingOdds} placeholder="1.98" onChange={(e) => set("closingOdds", e.target.value)} /></Field>
          <Field label={t("form.modelprob")}><Input type="number" step="0.1" value={b.modelProb} placeholder="52" onChange={(e) => set("modelProb", e.target.value)} /></Field>
        </div>
        <div className="trk-form__derived">
          <div><span>{t("form.impl")}</span><b>{impl == null ? "\u2014" : impl.toFixed(1) + "%"}</b></div>
          <div><span>Odds</span><b>{effOdds > 1 ? TRK.fmtOdds(effOdds, "american") + " · " + TRK.fmtOdds(effOdds, "fractional") : "\u2014"}</b></div>
          <div><span>{t("form.edge")}</span><b className={edge == null ? "" : edge >= 0 ? "trk-pos" : "trk-neg"}>{edge == null ? "\u2014" : TRK.fmtSignedPct(edge, 1)}</b></div>
          <div><span>{t("form.ev")}</span><b className={ev == null ? "" : ev >= 0 ? "trk-pos" : "trk-neg"}>{ev == null ? "\u2014" : TRK.fmtSignedPct(ev, 1)}</b></div>
          <div><span>CLV</span><b className={clv == null ? "" : clv >= 0 ? "trk-pos" : "trk-neg"}>{clv == null ? "\u2014" : TRK.fmtSignedPct(clv, 2)}</b></div>
        </div>
        <div className="trk-form__derived">
          <div><span>{t("form.kelly")}</span><b>{fullK == null ? "\u2014" : fullK.toFixed(2) + "%"}</b></div>
          <div><span>{t("form.kellysug")} ({kFrac}{"\u00d7"})</span><b>{sugg == null ? "\u2014" : TRK.fmtMoney(TRK.round(sugg, 0), cur)}</b></div>
          <div><span>{t("form.kellyvs")}</span><b className={kDelta == null ? "" : kDelta > 0 ? "trk-neg" : "trk-pos"}>
            {kDelta == null ? "\u2014" : (kDelta > 0 ? t("form.overbet") + " +" : t("form.underbet") + " \u2212") + Math.abs(kDelta).toFixed(2) + " pp"}</b></div>
        </div>
      </div>

      {/* Tags & notes */}
      <div className="trk-form__sec">
        <SecHead icon="edit">{t("form.sec.notes")}</SecHead>
        <Field label={t("form.tags")} span>
          <div className="trk-tagpick">
            {TRK.TAGS.map((tag) => (
              <button key={tag} type="button" className={"trk-tagpick__b" + (b.tags.includes(tag) ? " is-on" : "")}
                onClick={() => toggleTag(tag)}>{tag}</button>
            ))}
          </div>
        </Field>
        <Field label={t("form.notes")} hint={t("form.notesHint")} span>
          <textarea className="trk-input trk-textarea" rows="3" value={b.notes} onChange={(e) => set("notes", e.target.value)}></textarea>
        </Field>
      </div>

      <div className="trk-form__actions">
        {!isNew && <button className="trk-dangerlink" onClick={() => onDelete(b.id)}><Icon name="trash" size={15} /> {t("form.delete")}</button>}
        <div className="trk-form__actions-r">
          {!isNew && onDuplicate && <button className="trk-textlink trk-textlink--sm" onClick={() => onDuplicate(b)}><Icon name="copy" size={15} /> {t("form.duplicate")}</button>}
          <Btn variant="ghost" onClick={onCancel}>{t("form.cancel")}</Btn>
          <Btn variant="primary" icon="check" onClick={commit}>{t("form.save")}</Btn>
        </div>
      </div>
    </div>
  );
}

/* ---------- filter bar ---------- */
function uniq(arr) { return arr.filter((v, i) => v && arr.indexOf(v) === i); }

function Bets() {
  const { state, dispatch, t, lang, focusBet, clearFocus } = useTracker();
  const cur = state.settings.currency;
  const sportOpts = state.settings.sports || TRK.SPORTS;
  const bookOpts = TRK.bookOptions(state);
  const [q, setQ] = useState("");
  const [f, setF] = useState({ sport: "", league: "", market: "", tipster: "", book: "", result: "", tag: "", day: "" });
  const [editing, setEditing] = useState(null); // bet obj or null
  const [isNew, setIsNew] = useState(false);
  const [page, setPage] = useState(1);
  const perPage = 10;

  useEffect(() => {
    if (focusBet) {
      const b = state.bets.find((x) => x.id === focusBet);
      if (b) { setEditing(b); setIsNew(false); }
      clearFocus();
    }
  }, [focusBet]);

  const setFilter = (k, v) => setF((p) => ({ ...p, [k]: v }));
  const clearAll = () => { setQ(""); setF({ sport: "", league: "", market: "", tipster: "", book: "", result: "", tag: "", day: "" }); };
  const active = q || Object.values(f).some(Boolean);

  const dayOpts = [1, 2, 3, 4, 5, 6, 0].map((i) => ({
    value: String(i),
    label: new Date(Date.UTC(2024, 0, 7 + i)).toLocaleDateString(lang === "pt" ? "pt-BR" : "en-US", { weekday: "long", timeZone: "UTC" })
  }));

  const leagues = uniq(state.bets.map((b) => b.league));  const filtered = state.bets.filter((b) => {
    if (f.sport && b.sport !== f.sport) return false;
    if (f.league && b.league !== f.league) return false;
    if (f.market && b.market !== f.market) return false;
    if (f.tipster && b.tipster !== f.tipster) return false;
    if (f.book && b.book !== f.book) return false;
    if (f.result && b.result !== f.result) return false;
    if (f.tag && !b.tags.includes(f.tag)) return false;
    if (f.day !== "" && String(new Date(b.date + "T00:00:00").getDay()) !== f.day) return false;
    if (q) {
      const hay = (b.teamA + " " + b.teamB + " " + b.league + " " + b.market + " " + b.side + " " + b.player + " " + b.tipster).toLowerCase();
      if (!hay.includes(q.toLowerCase())) return false;
    }
    return true;
  }).sort((a, b) => TRK.byDate(b, a));

  const sub = TRK.summarize(filtered);

  // paginate — 10 per page, with a page selector at the foot of the table
  const totalPages = Math.max(1, Math.ceil(filtered.length / perPage));
  const curPage = Math.min(page, totalPages);
  const pageItems = filtered.slice((curPage - 1) * perPage, curPage * perPage);
  useEffect(() => { setPage(1); }, [q, f, filtered.length]);

  const openNew = () => { setEditing(blankBet(state)); setIsNew(true); };
  const save = (bet) => {
    dispatch(isNew ? { type: "add-bet", bet } : { type: "update-bet", bet });
    setEditing(null); setIsNew(false);
  };
  const del = (id) => { dispatch({ type: "delete-bet", id }); setEditing(null); setIsNew(false); };
  // open a fresh copy of a bet as a new (unsaved) entry
  const dup = (bet) => {
    const copy = { ...TRK.clone(bet), id: uid(), date: TRK.today(), result: "pending", closingOdds: "", returned: "" };
    setEditing(copy); setIsNew(true);
  };
  // one-click settle straight from the table row
  const settle = (bet, result) => dispatch({ type: "update-bet", bet: { ...bet, result } });

  return (
    <div className="trk-page">
      <SectionHead title={t("bets.title")} sub={t("bets.sub")}
        right={<Btn variant="primary" icon="plus" onClick={openNew}>{t("bets.add")}</Btn>} />

      {/* filter bar */}
      <Panel pad={18} className="trk-filters">
        <div className="trk-search">
          <Icon name="search" size={16} />
          <input value={q} placeholder={t("bets.search")} onChange={(e) => setQ(e.target.value)} />
        </div>
        <div className="trk-filterrow">
          <Select value={f.sport} onChange={(v) => setFilter("sport", v)} options={sportOpts} placeholder={t("an.all.sport")} />
          <Select value={f.league} onChange={(v) => setFilter("league", v)} options={leagues} placeholder={t("an.all.league")} />
          <Select value={f.market} onChange={(v) => setFilter("market", v)} options={TRK.marketOptions(state)} placeholder={t("an.all.market")} />
          <Select value={f.tipster} onChange={(v) => setFilter("tipster", v)} options={state.models.map((m) => m.name)} placeholder={t("an.all.model")} />
          <Select value={f.book} onChange={(v) => setFilter("book", v)} options={bookOpts} placeholder={t("an.all.book")} />
          <Select value={f.result} onChange={(v) => setFilter("result", v)} options={TRK.RESULTS.map((r) => ({ value: r, label: t("res." + r) }))} placeholder={t("an.all.result")} />
          <Select value={f.tag} onChange={(v) => setFilter("tag", v)} options={TRK.TAGS} placeholder={t("an.all.tag")} />
          <Select value={f.day} onChange={(v) => setFilter("day", v)} options={dayOpts} placeholder={t("an.all.day")} />
          {active && <button className="trk-textlink trk-textlink--sm" onClick={clearAll}>{t("bets.clear")}</button>}
        </div>
      </Panel>

      {/* summary strip */}
      <div className="trk-betsum">
        <span>{t("bets.showing")} <b>{filtered.length}</b> {t("bets.of")} {state.bets.length}</span>
        <span className="trk-betsum__sep"></span>
        <span>{t("dash.profit")}: <b className={sub.profit >= 0 ? "trk-pos" : "trk-neg"}>{TRK.fmtMoney(sub.profit, cur)}</b></span>
        <span>ROI: <b className={sub.roi >= 0 ? "trk-pos" : "trk-neg"}>{TRK.fmtSignedPct(sub.roi, 1)}</b></span>
        <span>{t("dash.turnover")}: <b>{TRK.fmtMoney(sub.staked, cur)}</b></span>
      </div>

      <Panel pad={0} className="trk-betspanel">
        {filtered.length ? (
          <div className="table-wrap trk-tablewrap">
            <table className="table trk-table trk-bettable">
              <thead>
                <tr>
                  <th style={{ textAlign: "left" }}>{t("col.date")}</th>
                  <th style={{ textAlign: "left" }}>{t("col.event")}</th>
                  <th style={{ textAlign: "left" }}>{t("col.side")}</th>
                  <th>{t("col.book")}</th>
                  <th>{t("col.odds")}</th>
                  <th>{t("col.stake")}</th>
                  <th>{t("col.clv")}</th>
                  <th>{t("col.result")}</th>
                  <th style={{ textAlign: "right" }}>{t("col.profit")}</th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                {pageItems.map((b) => {
                  const p = TRK.isSettled(b) ? TRK.betProfit(b) : null;
                  const clv = TRK.betCLV(b);
                  return (
                    <tr key={b.id} onClick={() => { setEditing(b); setIsNew(false); }}>
                      <td style={{ textAlign: "left", color: "var(--text-dim)" }}>{TRK.fmtDate(b.date)}</td>
                      <td style={{ textAlign: "left" }}>
                        <div className="trk-cellmain">{b.isParlay ? (t("form.parlay") + " · " + (b.legs ? b.legs.length : 0)) : (b.teamA + (b.teamB && b.teamB !== "\u2014" ? " v " + b.teamB : "") + (b.map ? " · " + b.map : ""))}</div>
                        <div className="trk-cellsub">{b.sport} · {b.league}{b.live ? " · LIVE" : ""}</div>
                      </td>
                      <td style={{ textAlign: "left" }}>
                        <div className="trk-cellmain">{b.side || "\u2014"}</div>
                        <div className="trk-cellsub">
                          {b.market}
                          {b.tags.slice(0, 1).map((tg) => <span key={tg} className="trk-tag trk-tag--mini">{tg}</span>)}
                        </div>
                      </td>
                      <td className="trk-cellsub2">{b.book}</td>
                      <td style={{ fontWeight: 700 }}>{TRK.fmtOdds(b.odds)}</td>
                      <td>{TRK.fmtMoney(b.stake, cur)}</td>
                      <td className={clv == null ? "trk-cellsub2" : clv >= 0 ? "trk-pos" : "trk-neg"} style={{ fontWeight: 700 }}>
                        {clv == null ? "\u2014" : TRK.fmtSignedPct(clv, 1)}</td>
                      <td>{b.result === "pending" ? (
                        <div className="trk-settle">
                          <button className="trk-settle__b is-w" onClick={(e) => { e.stopPropagation(); settle(b, "won"); }}>{t("res.won")}</button>
                          <button className="trk-settle__b is-l" onClick={(e) => { e.stopPropagation(); settle(b, "lost"); }}>{t("res.lost")}</button>
                          <button className="trk-settle__b is-v" onClick={(e) => { e.stopPropagation(); settle(b, "void"); }}>{t("res.void")}</button>
                        </div>
                      ) : <ResultBadge result={b.result} t={t} />}</td>
                      <td style={{ textAlign: "right", fontWeight: 700 }}
                        className={p == null ? "trk-cellsub2" : p > 0 ? "trk-pos" : p < 0 ? "trk-neg" : ""}>
                        {p == null ? "\u2014" : TRK.fmtMoney(TRK.round(p), cur)}</td>
                      <td style={{ width: 34 }}><span className="trk-rowedit"><Icon name="chevron" size={15} /></span></td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        ) : (
          <div style={{ padding: 32 }}>
            <EmptyState icon="bets" title={active ? t("bets.none") : t("bets.empty")}
              sub={active ? null : t("bets.emptySub")}
              action={active ? <Btn variant="ghost" onClick={clearAll}>{t("bets.clear")}</Btn> : <Btn variant="primary" icon="plus" onClick={openNew}>{t("bets.add")}</Btn>} />
          </div>
        )}
        {filtered.length > 0 && totalPages > 1 && (
          <div className="trk-pager">
            <button className="trk-pager__nav" disabled={curPage <= 1} onClick={() => setPage(curPage - 1)} aria-label="Previous">
              <Icon name="chevron" size={16} style={{ transform: "rotate(180deg)" }} />
            </button>
            {pageRange(curPage, totalPages).map((p, i) => (
              p === "\u2026"
                ? <span key={"e" + i} className="trk-pager__gap">…</span>
                : <button key={p} className={"trk-pager__pg" + (p === curPage ? " is-on" : "")} onClick={() => setPage(p)}>{p}</button>
            ))}
            <button className="trk-pager__nav" disabled={curPage >= totalPages} onClick={() => setPage(curPage + 1)} aria-label="Next">
              <Icon name="chevron" size={16} />
            </button>
          </div>
        )}
      </Panel>

      <Drawer open={!!editing} onClose={() => { setEditing(null); setIsNew(false); }}
        title={isNew ? t("form.new") : t("form.edit")}>
        {editing && <BetForm initial={editing} isNew={isNew} onSave={save} onDelete={del} onDuplicate={dup}
          onCancel={() => { setEditing(null); setIsNew(false); }} />}
      </Drawer>
    </div>
  );
}

Object.assign(window, { Bets, BetForm, blankBet });
