const { useState, useEffect, useCallback, useRef } = React;

// Reusable Chart.js wrapper — takes a config and re-renders on data change.
function ChartCanvas({ config, height = 220 }) {
  const canvasRef = useRef(null);
  const chartRef = useRef(null);
  useEffect(() => {
    if (!canvasRef.current || !window.Chart) return;
    if (chartRef.current) chartRef.current.destroy();
    chartRef.current = new window.Chart(canvasRef.current, config);
    return () => { if (chartRef.current) { chartRef.current.destroy(); chartRef.current = null; } };
  }, [JSON.stringify(config)]);
  return <div style={{ height, position: "relative" }}><canvas ref={canvasRef} /></div>;
}

const CHART_COLORS = {
  grid: "rgba(38, 50, 65, 0.6)",
  text: "#8b9aaf",
  accent: "#4ade80",
  accentFill: "rgba(74, 222, 128, 0.15)",
  alt: "#60a5fa",
  altFill: "rgba(96, 165, 250, 0.2)",
  warn: "#fbbf24",
  danger: "#f87171",
};

function baseChartOpts(extra = {}) {
  return {
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
      legend: { labels: { color: CHART_COLORS.text } },
      tooltip: { backgroundColor: "#131a22", borderColor: "#263241", borderWidth: 1 },
    },
    scales: {
      x: { ticks: { color: CHART_COLORS.text }, grid: { color: CHART_COLORS.grid } },
      y: { ticks: { color: CHART_COLORS.text }, grid: { color: CHART_COLORS.grid } },
    },
    ...extra,
  };
}

// The Go server now serves both the SPA and the API on the same origin,
// so relative URLs just work — regardless of whether we're on 8080 or 8001.
const API_BASE = "";
const PLAYER_ID_KEY = "marketbrawl.playerId";

function api(path, opts = {}) {
  const playerId = localStorage.getItem(PLAYER_ID_KEY);
  const headers = { "Content-Type": "application/json", ...(opts.headers || {}) };
  // Send X-Player-ID for guests. The server prefers the session cookie over
  // this header, so it's safely ignored once the user signs in with Google.
  if (playerId) headers["X-Player-ID"] = playerId;
  return fetch(`${API_BASE}${path}`, {
    ...opts,
    headers,
    credentials: "same-origin", // ensure the session cookie travels with every request
  }).then(async (r) => {
    const body = await r.json().catch(() => ({}));
    if (!r.ok) throw new Error(body.error || `HTTP ${r.status}`);
    return body;
  });
}

function fmtVP(n) {
  if (n == null) return "—";
  return `${Number(n).toFixed(2)} VP`;
}

function Login({ onLogin }) {
  const [name, setName] = useState("");
  const [err, setErr] = useState("");
  const [loading, setLoading] = useState(false);

  const submit = async (e) => {
    e.preventDefault();
    if (!name.trim()) return;
    setLoading(true);
    setErr("");
    try {
      const user = await api("/api/players", {
        method: "POST",
        body: JSON.stringify({ display_name: name.trim() }),
      });
      localStorage.setItem(PLAYER_ID_KEY, user.id);
      onLogin(user);
    } catch (e) {
      setErr(e.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="login-container">
      <HeroArt />
      <div style={{ display: "flex", justifyContent: "center", marginTop: "1rem" }}>
        <LogoFull size={56} />
      </div>
      <p className="tagline" style={{ marginTop: "1rem" }}>
        Predict the markets. Win Victory Points. No real money.
      </p>
      <div className="panel">
        <a
          href="/auth/login"
          className="primary"
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            gap: "0.6rem",
            width: "100%",
            padding: "0.75rem 1rem",
            textDecoration: "none",
            marginBottom: "1rem",
          }}
        >
          <svg width="18" height="18" viewBox="0 0 18 18" aria-hidden="true">
            <path fill="#4285F4" d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615z"/>
            <path fill="#34A853" d="M9 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z"/>
            <path fill="#FBBC05" d="M3.964 10.706A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.706V4.962H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.038l3.007-2.332z"/>
            <path fill="#EA4335" d="M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.962L3.964 7.294C4.672 5.167 6.656 3.58 9 3.58z"/>
          </svg>
          Sign in with Google
        </a>

        <div style={{ textAlign: "center", margin: "0.75rem 0", color: "var(--muted, #888)", fontSize: "0.85rem" }}>
          — or continue as guest —
        </div>

        <form onSubmit={submit}>
          {err && <div className="error">{err}</div>}
          <label>Choose a player name</label>
          <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Player 1" autoFocus />
          <button className="primary" style={{ width: "100%", marginTop: "1rem" }} disabled={loading}>
            {loading ? "Creating…" : "Enter MarketBrawl"}
          </button>
        </form>
      </div>
    </div>
  );
}

function Dashboard({ player }) {
  const [season, setSeason] = useState(null);
  const [round, setRound] = useState(null);
  const [portfolios, setPortfolios] = useState([]);
  const [markets, setMarkets] = useState([]);
  const [leaderboard, setLeaderboard] = useState([]);
  const [history, setHistory] = useState(null);
  const [err, setErr] = useState("");

  const load = useCallback(async () => {
    try {
      const [s, r, p, m, lb] = await Promise.all([
        api("/api/seasons/current").catch(() => null),
        api("/api/rounds/current").catch(() => null),
        api("/api/portfolios").catch(() => []),
        api("/api/markets").catch(() => []),
        api("/api/leaderboard").catch(() => []),
      ]);
      setSeason(s);
      setRound(r);
      setPortfolios(p || []);
      setMarkets(m || []);
      setLeaderboard(lb || []);
      if (p && p[0]) {
        api(`/api/portfolios/${p[0].id}/history`).then(setHistory).catch(() => setHistory(null));
      }
    } catch (e) {
      setErr(e.message);
    }
  }, []);

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

  const portfolio = portfolios[0];

  return (
    <div>
      {err && <div className="error">{err}</div>}
      <div className="grid grid-3">
        <div className="panel">
          <h3>Season</h3>
          {season ? (
            <>
              <div style={{ fontSize: "1.1rem" }}>{season.name}</div>
              <div className="muted">
                <span className={`status status-${season.status}`}>{season.status}</span> · {season.num_rounds} rounds
              </div>
            </>
          ) : <div className="muted">No active season. Create one from Admin.</div>}
        </div>
        <div className="panel">
          <h3>Current Round</h3>
          {round ? (
            <>
              <div style={{ fontSize: "1.1rem" }}>Round #{round.round_number}</div>
              <div className="muted"><span className={`status status-${round.status}`}>{round.status}</span></div>
            </>
          ) : <div className="muted">No round yet.</div>}
        </div>
        <div className="panel">
          <h3>Your Portfolio</h3>
          {portfolio ? (
            <>
              <div className="price vp">{fmtVP(portfolio.balance)}</div>
              <div className="muted">
                Wagered: {fmtVP(portfolio.total_wagered)} · Won: {fmtVP(portfolio.total_won)} · Lost: {fmtVP(portfolio.total_lost)}
              </div>
            </>
          ) : <div className="muted">No portfolio yet. Season must be active.</div>}
        </div>
      </div>

      <div className="grid grid-2" style={{ marginTop: "1rem" }}>
        <div className="panel">
          <h2>Portfolio Valuation</h2>
          <ValuationChart history={history} />
        </div>
        <div className="panel">
          <h2>Leaderboard — Current Balances</h2>
          <LeaderboardChart entries={leaderboard} currentUserId={player.id} />
        </div>
      </div>

      <div className="panel" style={{ marginTop: "1rem" }}>
        <h2>Market Prices</h2>
        <MarketPriceChart markets={markets} />
      </div>

      <div className="panel" style={{ marginTop: "1rem" }}>
        <h2>Open Markets</h2>
        {markets.length === 0 ? (
          <div className="muted">No markets available. Ask admin to open a round.</div>
        ) : (
          <div className="grid grid-3">
            {markets.map((m) => (
              <div key={m.id} className="panel market-card" style={{ margin: 0 }}>
                <div className="market-card-art">
                  <MarketIcon category={m.category} />
                  <h3 style={{ margin: 0 }}>{m.name || m.ticker}</h3>
                </div>
                <div className="muted" style={{ textTransform: "uppercase", fontSize: "0.75rem" }}>{m.category}</div>
                <div className="price">{m.current_price ? `${m.unit || "$"}${Number(m.current_price).toFixed(2)}` : "—"}</div>
                <div className="muted">Min {fmtVP(m.min_bet)} · Max {fmtVP(m.max_bet)}</div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

function Markets({ player, onBetPlaced }) {
  const [markets, setMarkets] = useState([]);
  const [portfolios, setPortfolios] = useState([]);
  const [err, setErr] = useState("");

  const load = useCallback(async () => {
    try {
      const [m, p] = await Promise.all([
        api("/api/markets").catch(() => []),
        api("/api/portfolios").catch(() => []),
      ]);
      setMarkets(m || []);
      setPortfolios(p || []);
    } catch (e) { setErr(e.message); }
  }, []);

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

  return (
    <div>
      {err && <div className="error">{err}</div>}
      {markets.length === 0 && <div className="panel muted">No markets available.</div>}
      {markets.map((m) => (
        <MarketBet key={m.id} market={m} portfolio={portfolios[0]} onPlaced={() => { load(); onBetPlaced?.(); }} />
      ))}
    </div>
  );
}

function MarketBet({ market, portfolio, onPlaced }) {
  const [direction, setDirection] = useState("over");
  const [target, setTarget] = useState((market.current_price * 1.05).toFixed(2));
  const [wager, setWager] = useState("10");
  const [status, setStatus] = useState({});
  const [submitting, setSubmitting] = useState(false);

  const placeBet = async (e) => {
    e.preventDefault();
    if (!portfolio) { setStatus({ err: "No portfolio — enrol in active season first." }); return; }
    setSubmitting(true);
    setStatus({});
    try {
      await api("/api/bets", {
        method: "POST",
        body: JSON.stringify({
          market_id: market.id,
          portfolio_id: portfolio.id,
          direction,
          target_price: Number(target),
          wager_amount: Number(wager),
        }),
      });
      setStatus({ ok: `Bet placed: ${direction.toUpperCase()} ${target} for ${wager} VP` });
      onPlaced?.();
    } catch (e) { setStatus({ err: e.message }); }
    finally { setSubmitting(false); }
  };

  return (
    <div className="panel">
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
        <div style={{ display: "flex", alignItems: "center", gap: "0.75rem" }}>
          <MarketIcon category={market.category} size={30} />
          <div>
            <h2 style={{ margin: 0 }}>{market.name || market.ticker}</h2>
            <div className="muted">{market.category} · {market.ticker}</div>
          </div>
        </div>
        <div style={{ textAlign: "right" }}>
          <div className="price">{market.current_price ? `${market.unit || "$"}${Number(market.current_price).toFixed(2)}` : "—"}</div>
          <div className="muted">Current price</div>
        </div>
      </div>
      <form onSubmit={placeBet} style={{ marginTop: "1rem" }}>
        {status.err && <div className="error">{status.err}</div>}
        {status.ok && <div className="success">{status.ok}</div>}
        <div className="row">
          <div>
            <label>Direction</label>
            <select value={direction} onChange={(e) => setDirection(e.target.value)}>
              <option value="over">OVER</option>
              <option value="under">UNDER</option>
            </select>
          </div>
          <div>
            <label>Target Price</label>
            <input type="number" step="0.05" value={target} onChange={(e) => setTarget(e.target.value)} />
          </div>
          <div>
            <label>Wager (VP)</label>
            <input type="number" step="0.05" min={market.min_bet} max={market.max_bet} value={wager} onChange={(e) => setWager(e.target.value)} />
          </div>
          <div style={{ alignSelf: "end" }}>
            <button className="primary" disabled={submitting}>{submitting ? "…" : "Place Bet"}</button>
          </div>
        </div>
      </form>
    </div>
  );
}

function Portfolio({ player }) {
  const [bets, setBets] = useState([]);
  const [portfolios, setPortfolios] = useState([]);
  const [history, setHistory] = useState(null);
  const [err, setErr] = useState("");

  const load = useCallback(async () => {
    try {
      const [b, p] = await Promise.all([
        api("/api/bets").catch(() => []),
        api("/api/portfolios").catch(() => []),
      ]);
      setBets(b || []);
      setPortfolios(p || []);
      if (p && p[0]) {
        api(`/api/portfolios/${p[0].id}/history`).then(setHistory).catch(() => setHistory(null));
      }
    } catch (e) { setErr(e.message); }
  }, []);
  useEffect(() => { load(); }, [load]);

  const portfolio = portfolios[0];

  return (
    <div>
      {err && <div className="error">{err}</div>}
      {portfolio && (
        <div className="panel">
          <h2>Balance</h2>
          <div className="price vp">{fmtVP(portfolio.balance)}</div>
          <div className="grid grid-3" style={{ marginTop: "0.75rem" }}>
            <div><div className="muted">Total Wagered</div><div>{fmtVP(portfolio.total_wagered)}</div></div>
            <div><div className="muted">Total Won</div><div className="vp">{fmtVP(portfolio.total_won)}</div></div>
            <div><div className="muted">Total Lost</div><div className="neg">{fmtVP(portfolio.total_lost)}</div></div>
          </div>
        </div>
      )}
      <div className="grid grid-2">
        <div className="panel">
          <h2>Balance Over Time</h2>
          <ValuationChart history={history} />
        </div>
        <div className="panel">
          <h2>Round P&amp;L</h2>
          <RoundPnLChart history={history} />
        </div>
      </div>
      <div className="panel">
        <h2>Your Bets (Current Round)</h2>
        {bets.length === 0 ? <div className="muted">No bets placed yet.</div> : (
          <table>
            <thead>
              <tr><th>Direction</th><th>Target</th><th>Wager</th><th>Odds</th><th>Status</th><th>Payout</th></tr>
            </thead>
            <tbody>
              {bets.map((b) => (
                <tr key={b.id}>
                  <td>
                    <span className="bet-row-badge">
                      <DirectionBadge direction={b.direction} />
                      {b.direction.toUpperCase()}
                    </span>
                  </td>
                  <td>{Number(b.target_price).toFixed(2)}</td>
                  <td>{fmtVP(b.wager_amount)}</td>
                  <td>{Number(b.odds_multiplier).toFixed(2)}x</td>
                  <td><span className={`status status-${b.status}`}>{b.status}</span></td>
                  <td>{b.payout ? fmtVP(b.payout) : "—"}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

function Leaderboard() {
  const [entries, setEntries] = useState([]);
  const [err, setErr] = useState("");
  useEffect(() => {
    api("/api/leaderboard").then(setEntries).catch((e) => setErr(e.message));
  }, []);
  return (
    <div className="panel">
      <h2>Season Leaderboard</h2>
      {err && <div className="error">{err}</div>}
      {entries.length === 0 ? <div className="muted">No entries yet.</div> : (
        <table>
          <thead>
            <tr><th>Rank</th><th>Player</th><th>Balance</th><th>Total Won</th><th>Total Lost</th></tr>
          </thead>
          <tbody>
            {entries.map((e, i) => (
              <tr key={e.user_id}>
                <td>#{i + 1}</td>
                <td>
                  <span className="persona-cell">
                    <PersonaAvatar persona={e.is_bot ? e.bot_persona : null} size={32} />
                    <span>{e.display_name}</span>
                  </span>
                </td>
                <td className="vp">{fmtVP(e.balance)}</td>
                <td>{fmtVP(e.total_won)}</td>
                <td>{fmtVP(e.total_lost)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </div>
  );
}

function Admin({ onChange }) {
  const [msg, setMsg] = useState({});
  const [seasonName, setSeasonName] = useState("Season 1");
  const [numRounds, setNumRounds] = useState(4);

  const post = async (path, body) => {
    setMsg({});
    try {
      await api(path, { method: "POST", body: body ? JSON.stringify(body) : undefined });
      setMsg({ ok: `${path} succeeded` });
      onChange?.();
    } catch (e) { setMsg({ err: e.message }); }
  };

  return (
    <div>
      <div className="panel">
        <h2>Admin Controls</h2>
        <p className="muted">Auth is disabled in closed beta — anyone can drive the game loop.</p>
        {msg.err && <div className="error">{msg.err}</div>}
        {msg.ok && <div className="success">{msg.ok}</div>}
        <h3>Create + Activate Season</h3>
        <div className="row">
          <input value={seasonName} onChange={(e) => setSeasonName(e.target.value)} placeholder="Season name" />
          <input type="number" min="1" value={numRounds} onChange={(e) => setNumRounds(Number(e.target.value))} />
          <button className="primary" onClick={() => post("/api/admin/season", { name: seasonName, num_rounds: numRounds })}>
            Create Season
          </button>
        </div>
        <h3 style={{ marginTop: "1.5rem" }}>Round Lifecycle</h3>
        <div className="row">
          <button className="ghost" onClick={() => post("/api/admin/round/open")}>Open Round</button>
          <button className="ghost" onClick={() => post("/api/admin/prices/refresh")}>Refresh Prices</button>
          <button className="ghost" onClick={() => post("/api/admin/bots/trigger")}>Trigger Bots</button>
          <button className="ghost" onClick={() => post("/api/admin/round/resolve")}>Resolve Round</button>
        </div>
      </div>
    </div>
  );
}

function ValuationChart({ history }) {
  if (!history || !history.points || history.points.length === 0) {
    return <div className="muted" style={{ padding: "1rem 0" }}>No round history yet — valuation chart appears after the first round resolves.</div>;
  }
  const initial = history.initial_balance || 10000;
  let running = initial;
  const labels = ["Start"];
  const values = [initial];
  for (const p of history.points) {
    running = running + (Number(p.net_pnl) || 0) + (Number(p.bonus_earned) || 0);
    labels.push(`R${p.round_number}`);
    values.push(Number(running.toFixed(2)));
  }
  const config = {
    type: "line",
    data: {
      labels,
      datasets: [{
        label: "Balance (VP)",
        data: values,
        borderColor: CHART_COLORS.accent,
        backgroundColor: CHART_COLORS.accentFill,
        fill: true,
        tension: 0.25,
        pointRadius: 4,
        pointBackgroundColor: CHART_COLORS.accent,
      }],
    },
    options: baseChartOpts({
      plugins: {
        legend: { labels: { color: CHART_COLORS.text } },
        tooltip: {
          callbacks: { label: (ctx) => `${Number(ctx.parsed.y).toFixed(2)} VP` },
          backgroundColor: "#131a22", borderColor: "#263241", borderWidth: 1,
        },
      },
    }),
  };
  return <ChartCanvas config={config} height={240} />;
}

function LeaderboardChart({ entries, currentUserId }) {
  if (!entries || entries.length === 0) {
    return <div className="muted" style={{ padding: "1rem 0" }}>No players yet.</div>;
  }
  const top = entries.slice(0, 10);
  const config = {
    type: "bar",
    data: {
      labels: top.map((e) => e.display_name + (e.is_bot ? " 🤖" : "")),
      datasets: [{
        label: "Balance (VP)",
        data: top.map((e) => Number(e.balance)),
        backgroundColor: top.map((e) =>
          e.user_id === currentUserId ? CHART_COLORS.accent : e.is_bot ? CHART_COLORS.altFill : CHART_COLORS.alt
        ),
        borderColor: top.map((e) =>
          e.user_id === currentUserId ? CHART_COLORS.accent : CHART_COLORS.alt
        ),
        borderWidth: 1,
      }],
    },
    options: baseChartOpts({
      indexAxis: "y",
      plugins: { legend: { display: false } },
    }),
  };
  return <ChartCanvas config={config} height={240} />;
}

function RoundPnLChart({ history }) {
  if (!history || !history.points || history.points.length === 0) {
    return <div className="muted" style={{ padding: "1rem 0" }}>No resolved rounds yet.</div>;
  }
  const points = history.points;
  const pnl = points.map((p) => Number(p.net_pnl) + Number(p.bonus_earned));
  const config = {
    type: "bar",
    data: {
      labels: points.map((p) => `R${p.round_number}`),
      datasets: [{
        label: "Net P&L (VP)",
        data: pnl,
        backgroundColor: pnl.map((v) => v >= 0 ? CHART_COLORS.accentFill : "rgba(248, 113, 113, 0.2)"),
        borderColor: pnl.map((v) => v >= 0 ? CHART_COLORS.accent : CHART_COLORS.danger),
        borderWidth: 1,
      }],
    },
    options: baseChartOpts({ plugins: { legend: { display: false } } }),
  };
  return <ChartCanvas config={config} height={240} />;
}

function MarketPriceChart({ markets }) {
  if (!markets || markets.length === 0) {
    return <div className="muted" style={{ padding: "1rem 0" }}>No markets yet.</div>;
  }
  const config = {
    type: "bar",
    data: {
      labels: markets.map((m) => m.name || m.ticker),
      datasets: [
        {
          label: "Opening Price",
          data: markets.map((m) => Number(m.opening_price) || 0),
          backgroundColor: CHART_COLORS.altFill,
          borderColor: CHART_COLORS.alt,
          borderWidth: 1,
        },
        {
          label: "Current Price",
          data: markets.map((m) => Number(m.current_price) || 0),
          backgroundColor: CHART_COLORS.accentFill,
          borderColor: CHART_COLORS.accent,
          borderWidth: 1,
        },
      ],
    },
    options: baseChartOpts(),
  };
  return <ChartCanvas config={config} height={260} />;
}

function App() {
  const [player, setPlayer] = useState(null);
  const [checking, setChecking] = useState(true);
  const [tab, setTab] = useState("dashboard");
  const [refresh, setRefresh] = useState(0);

  useEffect(() => {
    // Session cookie takes priority: if Google OAuth set one, use that user.
    api("/api/auth/me")
      .then((res) => {
        if (res && res.user) {
          setPlayer(res.user);
          setChecking(false);
          return;
        }
        // Fallback: guest/local account via X-Player-ID header.
        const id = localStorage.getItem(PLAYER_ID_KEY);
        if (!id) { setChecking(false); return; }
        api(`/api/players/${id}`)
          .then((u) => setPlayer(u))
          .catch(() => localStorage.removeItem(PLAYER_ID_KEY))
          .finally(() => setChecking(false));
      })
      .catch(() => {
        // /api/auth/me errored — try local fallback anyway.
        const id = localStorage.getItem(PLAYER_ID_KEY);
        if (!id) { setChecking(false); return; }
        api(`/api/players/${id}`)
          .then((u) => setPlayer(u))
          .catch(() => localStorage.removeItem(PLAYER_ID_KEY))
          .finally(() => setChecking(false));
      });
  }, []);

  if (checking) return <div className="app"><div className="muted">Loading…</div></div>;
  if (!player) return <Login onLogin={setPlayer} />;

  const logout = async () => {
    // Clear both the local guest identity and the server-side session cookie.
    localStorage.removeItem(PLAYER_ID_KEY);
    try {
      await fetch("/auth/logout", { method: "POST", credentials: "same-origin" });
    } catch (_) { /* best effort */ }
    setPlayer(null);
  };

  const tabs = [
    ["dashboard", "Dashboard"],
    ["markets", "Markets"],
    ["portfolio", "Portfolio"],
    ["leaderboard", "Leaderboard"],
    ["admin", "Admin"],
  ];

  return (
    <div className="app">
      <header>
        <div>
          <LogoFull size={38} />
          <div className="muted" style={{ marginTop: "0.4rem" }}>Welcome, {player.display_name}</div>
        </div>
        <nav>
          {tabs.map(([id, label]) => (
            <button key={id} className={tab === id ? "active" : ""} onClick={() => setTab(id)}>{label}</button>
          ))}
          <button onClick={logout}>Logout</button>
        </nav>
      </header>
      <div className="banner">VICTORY POINTS ONLY — NOT REAL CURRENCY</div>
      <div key={refresh}>
        {tab === "dashboard" && <Dashboard player={player} />}
        {tab === "markets" && <Markets player={player} onBetPlaced={() => setRefresh((r) => r + 1)} />}
        {tab === "portfolio" && <Portfolio player={player} />}
        {tab === "leaderboard" && <Leaderboard />}
        {tab === "admin" && <Admin onChange={() => setRefresh((r) => r + 1)} />}
      </div>
    </div>
  );
}

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