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

/* ------------------------------------------------------------------ */
/*  GRAM — Telegram Mini App prototype (virtual-currency casino demo) */
/*  Palette: bg #000000 · card #16171c · accent #29a9f5 · gold #ffb703 */
/*           text #ffffff · muted #8b8d97 · border #2a2b32            */
/*  Typeface: system default (no custom font loaded)                  */
/* ------------------------------------------------------------------ */

const SYS_FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';

const BG = "#000000";
const CARD = "#16171c";
const ACCENT = "#29a9f5";
const ACCENT2 = "#ffb703";
const TEXT = "#ffffff";
const MUTED = "#8b8d97";
const BORDER = "#2a2b32";
const PVP_ACCENT = "#a855f7";

const STARTING_BALANCE = 500;
const DAILY_COOLDOWN_MS = 24 * 60 * 60 * 1000;

/* --- backend wiring for real TON deposits ---------------------------
   Point this at wherever you deploy gram-casino-backend (the standalone
   NestJS project). Everything else in this file — spins, PvP, local
   history — still runs entirely client-side; only the wallet balance now
   has a real, server-verified floor: whatever the on-chain deposit
   watcher has actually credited. */
const API_BASE = "https://eleven-words-camp.loca.lt";


async function apiLogin() {
  const initData = window.Telegram?.WebApp?.initData || "";
  const res = await fetch(`${API_BASE}/auth/telegram`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ initData }),
  });
  if (!res.ok) throw new Error("login failed");
  return res.json(); // { token, userId }
}
async function apiGet(path, token) {
  const res = await fetch(`${API_BASE}${path}`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) throw new Error(`${path} failed`);
  return res.json();
}
async function apiPost(path, token, body) {
  const res = await fetch(`${API_BASE}${path}`, {
    method: "POST",
    headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
    body: JSON.stringify(body),
  });
  if (!res.ok) throw new Error(`${path} failed`);
  return res.json();
}


const WHEEL_SEGMENTS = [
  { label: "0", mult: 0, color: "#1a2744" },
  { label: "×2", mult: 2, color: "#1148a8" },
  { label: "×0.5", mult: 0.5, color: "#12203f" },
  { label: "×5", mult: 5, color: "#7a1fd6" },
  { label: "×1", mult: 1, color: "#1a3a7a" },
  { label: "×3", mult: 3, color: "#0f6fb0" },
  { label: "0", mult: 0, color: "#1a2744" },
  { label: "×10", mult: 10, color: "#ff8a1f" },
];

const BOT_NAMES = [
  "Nebula_88", "Voidcap_TON", "PixelKhan", "Ghostbid_7",
  "Ariza_Dust", "Coldstar_99", "Lumen_Frog", "Zar_Havoc",
];

function fmt(n) {
  return Math.round(n * 100) / 100;
}

function uid() {
  return Math.random().toString(36).slice(2, 10);
}

/* ------------------------------ storage ---------------------------- */

async function loadProfile() {
  try {
    const res = await window.storage.get("profile", false);
    return res ? JSON.parse(res.value) : null;
  } catch {
    return null;
  }
}
async function saveProfile(profile) {
  try {
    await window.storage.set("profile", JSON.stringify(profile), false);
  } catch {
    /* best effort */
  }
}
async function loadHistory() {
  try {
    const res = await window.storage.get("history", false);
    return res ? JSON.parse(res.value) : [];
  } catch {
    return [];
  }
}
async function saveHistory(history) {
  try {
    await window.storage.set("history", JSON.stringify(history.slice(0, 40)), false);
  } catch {
    /* best effort */
  }
}

/* ------------------------------ icons ------------------------------ */

const Icon = {
  profile: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <circle cx="12" cy="8" r="3.4" stroke="currentColor" strokeWidth="1.8" />
      <path d="M4.5 19.2c1.6-3.4 4.4-5.1 7.5-5.1s5.9 1.7 7.5 5.1" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
    </svg>
  ),
  games: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <rect x="3.5" y="7" width="17" height="11" rx="3" stroke="currentColor" strokeWidth="1.8" />
      <circle cx="8.5" cy="12.5" r="1.4" fill="currentColor" />
      <circle cx="15.5" cy="12.5" r="1.4" fill="currentColor" />
      <path d="M8 4.5c1.2-1 2.6-1.5 4-1.5s2.8.5 4 1.5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
    </svg>
  ),
  swords: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <path d="M4 20 15 9M4 20l2.2-.3L6.5 17.5M15 9l3-3 2.5.5L20 9l-3 3M15 9l-2-2M9 15l-2 2" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" />
      <path d="M20 4 9 15" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" opacity="0.55" />
    </svg>
  ),
  coin: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <circle cx="12" cy="12" r="8.5" stroke="currentColor" strokeWidth="1.8" />
      <path d="M12 7.5v9M9.4 9.6c0-1.1 1.1-1.9 2.6-1.9s2.6.7 2.6 1.7c0 2.3-5.2 1-5.2 3.2 0 1 1.1 1.8 2.6 1.8s2.6-.8 2.6-1.9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
    </svg>
  ),
  bolt: (p) => (
    <svg viewBox="0 0 24 24" fill="currentColor" {...p}>
      <path d="M13 2 4 14h6l-1 8 9-12h-6l1-8Z" />
    </svg>
  ),
  clock: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <circle cx="12" cy="12" r="8.5" stroke="currentColor" strokeWidth="1.7" />
      <path d="M12 7.5V12l3 2" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  ),
  crown: (p) => (
    <svg viewBox="0 0 24 24" fill="currentColor" {...p}>
      <path d="M3 8l4 3 5-6 5 6 4-3-1.6 9.5H4.6L3 8Zm2.4 12h13.2v1.6H5.4V20Z" />
    </svg>
  ),
};

/* ------------------------------ shell ------------------------------- */

function GramApp() {
  // no custom font — using the system default typeface

  const [profile, setProfile] = useState(null);
  const [history, setHistory] = useState([]);
  const [ready, setReady] = useState(false);
  const [tab, setTab] = useState("games");
  const [toast, setToast] = useState(null);

  // --- real-money session (backend auth + deposit balance) ---
  const [authToken, setAuthToken] = useState(null);
  const lastKnownServerBalance = useRef(null);

  useEffect(() => {
    (async () => {
      let p = await loadProfile();
      if (!p) {
        p = {
          name: "Player" + Math.floor(1000 + Math.random() * 9000),
          balance: STARTING_BALANCE,
          lastFreeSpin: 0,
          wins: 0,
          losses: 0,
          wagered: 0,
          createdAt: Date.now(),
        };
        await saveProfile(p);
      }
      const h = await loadHistory();
      setProfile(p);
      setHistory(h);
      setReady(true);
    })();
  }, []);

  // Log in to the real backend (Telegram initData -> JWT), then fold any
  // confirmed on-chain deposit into the local balance. This never LOWERS
  // the local balance (so in-game wins/losses aren't clobbered) — it only
  // adds newly-detected deposits on top, the moment the poller confirms them.
  useEffect(() => {
    let cancelled = false;
    let poll;
    (async () => {
      try {
        const { token } = await apiLogin();
        if (cancelled) return;
        setAuthToken(token);
        const check = async () => {
          try {
            const { balance: serverBalance } = await apiGet("/deposit/balance", token);
            if (lastKnownServerBalance.current == null) {
              lastKnownServerBalance.current = serverBalance;
              return;
            }
            const delta = serverBalance - lastKnownServerBalance.current;
            lastKnownServerBalance.current = serverBalance; // always resync, regardless of sign
            if (delta > 0) {
              setProfile((prev) => {
                if (!prev) return prev;
                const next = { ...prev, balance: fmt(prev.balance + delta) };
                saveProfile(next);
                return next;
              });
              pushToast(`Deposit confirmed: +${fmt(delta)} GRAM`, "win");
            }
          } catch {
            /* backend unreachable — silently retry next tick */
          }
        };
        await check();
        poll = setInterval(check, 8000);
      } catch {
        /* not inside Telegram, or backend unreachable — app still works locally */
      }
    })();
    return () => {
      cancelled = true;
      if (poll) clearInterval(poll);
    };
  }, []);

  const commit = useCallback((nextProfile, entry) => {
    setProfile(nextProfile);
    saveProfile(nextProfile);
    if (entry) {
      setHistory((prev) => {
        const next = [entry, ...prev].slice(0, 40);
        saveHistory(next);
        return next;
      });
    }
  }, []);

  // Adjust the local balance immediately (used by withdrawal requests, which
  // deduct on the server right away) and keep our "last known server
  // balance" reference in sync so the deposit-poller doesn't misread this
  // as a fresh deposit later.
  const applyLocalBalanceDelta = useCallback((delta) => {
    if (lastKnownServerBalance.current != null) {
      lastKnownServerBalance.current += delta;
    }
    setProfile((prev) => {
      if (!prev) return prev;
      const next = { ...prev, balance: fmt(prev.balance + delta) };
      saveProfile(next);
      return next;
    });
  }, []);

  const pushToast = useCallback((msg, kind = "info") => {
    setToast({ id: uid(), msg, kind });
  }, []);

  useEffect(() => {
    if (!toast) return;
    const t = setTimeout(() => setToast(null), 2600);
    return () => clearTimeout(t);
  }, [toast]);

  if (!ready) {
    return (
      <Shell>
        <div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center" }}>
          <div style={{ color: "#29a9f5", fontFamily: SYS_FONT, fontSize: 14, letterSpacing: 1 }}>
            loading vault…
          </div>
        </div>
      </Shell>
    );
  }

  return (
    <Shell>
      <TopBar balance={profile.balance} name={profile.name} onDeposit={() => setTab("deposit")} />
      <div style={{ flex: 1, overflowY: "auto", WebkitOverflowScrolling: "touch", paddingBottom: 74 }}>
        {tab === "profile" && (
          <ProfileTab profile={profile} history={history} authToken={authToken} pushToast={pushToast} onBalanceDelta={applyLocalBalanceDelta} />
        )}
        {tab === "games" && <GamesTab onOpenSpin={() => setTab("spin")} onOpenPvp={() => setTab("pvp")} profile={profile} />}
        {tab === "spin" && (
          <DailySpinTab profile={profile} commit={commit} pushToast={pushToast} onBack={() => setTab("games")} />
        )}
        {tab === "pvp" && (
          <PvpSpinTab profile={profile} commit={commit} pushToast={pushToast} onBack={() => setTab("games")} />
        )}
        {tab === "deposit" && <DepositTab authToken={authToken} pushToast={pushToast} onBack={() => setTab("games")} />}
      </div>
      <BottomNav tab={tab} setTab={setTab} />
      <Toast toast={toast} />
    </Shell>
  );
}

/* ------------------------------ deposit ------------------------------ */

function DepositTab({ authToken, pushToast, onBack }) {
  const [info, setInfo] = useState(null);
  const [error, setError] = useState(null);
  const [copied, setCopied] = useState(false);
  const [amount, setAmount] = useState("");
  const [step, setStep] = useState("amount"); // "amount" -> "address"

  useEffect(() => {
    if (!authToken) {
      setError("Open this inside Telegram to deposit.");
      return;
    }
    apiGet("/deposit/info", authToken)
      .then(setInfo)
      .catch(() => setError("Couldn't reach the deposit server. Try again shortly."));
  }, [authToken]);

  const copy = (text) => {
    navigator.clipboard?.writeText(text).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    });
  };

  const amountNum = parseFloat(amount);
  const canContinue = !error && Number.isFinite(amountNum) && amountNum > 0;

  return (
    <div style={{ padding: "6px 18px 24px", position: "relative", zIndex: 1 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 18 }}>
        <button
          onClick={() => (step === "address" ? setStep("amount") : onBack())}
          style={{ background: CARD, border: `1px solid ${BORDER}`, borderRadius: 999, width: 34, height: 34, color: TEXT, cursor: "pointer" }}
        >
          ←
        </button>
        <div style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 17, color: TEXT }}>Deposit TON</div>
      </div>

      {error && (
        <div style={{ background: CARD, border: `1px solid ${BORDER}`, borderRadius: 14, padding: 16, color: MUTED, fontFamily: SYS_FONT, fontSize: 13 }}>
          {error}
        </div>
      )}

      {!error && step === "amount" && (
        <>
          <div style={{ fontFamily: SYS_FONT, fontSize: 13, color: MUTED, marginBottom: 10 }}>
            How much TON do you want to deposit?
          </div>
          <div
            style={{
              background: CARD, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 16,
              display: "flex", alignItems: "center", gap: 10, marginBottom: 14,
            }}
          >
            <input
              type="number"
              inputMode="decimal"
              min="0"
              step="0.1"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
              placeholder="0.0"
              style={{
                flex: 1, background: "transparent", border: "none", outline: "none",
                fontFamily: SYS_FONT, fontWeight: 800, fontSize: 22, color: TEXT,
              }}
            />
            <span style={{ fontFamily: SYS_FONT, fontWeight: 700, fontSize: 14, color: MUTED }}>TON</span>
          </div>

          <div style={{ display: "flex", gap: 8, marginBottom: 18 }}>
            {[1, 5, 10].map((v) => (
              <button
                key={v}
                onClick={() => setAmount(String(v))}
                style={{
                  flex: 1, background: CARD, border: `1px solid ${BORDER}`, borderRadius: 12,
                  padding: "9px 0", color: TEXT, fontFamily: SYS_FONT, fontWeight: 700, fontSize: 13, cursor: "pointer",
                }}
              >
                {v} TON
              </button>
            ))}
          </div>

          <button
            onClick={() => canContinue && setStep("address")}
            disabled={!canContinue}
            style={{
              width: "100%", border: "none", borderRadius: 14, padding: "14px 0",
              fontFamily: SYS_FONT, fontWeight: 800, fontSize: 15,
              background: canContinue ? ACCENT : BORDER,
              color: canContinue ? "#04121c" : MUTED,
              cursor: canContinue ? "pointer" : "not-allowed",
            }}
          >
            Continue
          </button>
        </>
      )}

      {!error && step === "address" && info && (
        <>
          <div
            style={{
              background: CARD, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 16,
              marginBottom: 14, display: "flex", alignItems: "baseline", justifyContent: "space-between",
            }}
          >
            <span style={{ fontFamily: SYS_FONT, fontSize: 12, color: MUTED }}>Sending</span>
            <span style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 18, color: TEXT }}>{amountNum} TON</span>
          </div>

          <div style={{ background: CARD, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 18, marginBottom: 12 }}>
            <div style={{ fontFamily: SYS_FONT, fontSize: 11.5, color: MUTED, marginBottom: 6, textTransform: "uppercase", letterSpacing: 0.6 }}>
              Send TON to
            </div>
            <div
              onClick={() => copy(info.address)}
              style={{ fontFamily: "monospace", fontSize: 13, color: TEXT, wordBreak: "break-all", cursor: "pointer", lineHeight: 1.5 }}
            >
              {info.address}
            </div>
          </div>

          <div style={{ background: CARD, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 18, marginBottom: 12 }}>
            <div style={{ fontFamily: SYS_FONT, fontSize: 11.5, color: MUTED, marginBottom: 6, textTransform: "uppercase", letterSpacing: 0.6 }}>
              With this comment/memo (required!)
            </div>
            <div
              onClick={() => copy(info.memo)}
              style={{
                fontFamily: "monospace", fontWeight: 800, fontSize: 18, color: ACCENT2, cursor: "pointer",
                background: "rgba(255,183,3,0.08)", borderRadius: 10, padding: "8px 10px", display: "inline-block",
              }}
            >
              {info.memo}
            </div>
          </div>

          {copied && (
            <div style={{ fontFamily: SYS_FONT, fontSize: 12, color: ACCENT, marginBottom: 12 }}>Copied ✓</div>
          )}

          <div style={{ fontFamily: SYS_FONT, fontSize: 12.5, color: MUTED, lineHeight: 1.6 }}>
            Open your wallet (Tonkeeper, Tonhub, …), send <b style={{ color: TEXT }}>{amountNum} TON</b> to the
            address above, and <b style={{ color: TEXT }}>make sure to paste the memo in the comment field</b> —
            without it we can't tell the deposit is yours. Your balance updates automatically within about a
            minute of the transaction confirming on-chain, no need to do anything else here.
          </div>
        </>
      )}
    </div>
  );
}

function Shell({ children }) {
  return (
    <div
      style={{
        width: "100%",
        maxWidth: 420,
        height: 760,
        margin: "0 auto",
        position: "relative",
        display: "flex",
        flexDirection: "column",
        background: BG,
        borderRadius: 24,
        overflow: "hidden",
        fontFamily: SYS_FONT,
        color: TEXT,
        boxShadow: "0 0 0 1px rgba(41,169,245,0.15), 0 30px 80px rgba(0,0,0,0.6)",
      }}
    >
      <BackgroundFX />
      {children}
    </div>
  );
}

function BackgroundFX() {
  return (
    <div style={{ position: "absolute", inset: 0, pointerEvents: "none", overflow: "hidden", zIndex: 0 }}>
      <div
        style={{
          position: "absolute",
          top: -140,
          left: "50%",
          transform: "translateX(-50%)",
          width: 420,
          height: 420,
          borderRadius: "50%",
          background: "radial-gradient(circle, rgba(41,169,245,0.22) 0%, rgba(41,169,245,0) 70%)",
        }}
      />
      <div
        style={{
          position: "absolute",
          bottom: -160,
          right: -100,
          width: 320,
          height: 320,
          borderRadius: "50%",
          background: "radial-gradient(circle, rgba(41,169,245,0.14) 0%, rgba(41,169,245,0) 70%)",
        }}
      />
      <div
        style={{
          position: "absolute",
          top: "38%",
          left: -120,
          width: 260,
          height: 260,
          borderRadius: "50%",
          background: "radial-gradient(circle, rgba(41,169,245,0.1) 0%, rgba(41,169,245,0) 70%)",
        }}
      />
    </div>
  );
}

function TopBar({ balance, name, onDeposit }) {
  return (
    <div
      style={{
        position: "relative",
        zIndex: 1,
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        padding: "18px 18px 14px",
      }}
    >
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <div
          style={{
            width: 34,
            height: 34,
            borderRadius: "50%",
            background: CARD,
            border: `1.5px solid ${BORDER}`,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            fontFamily: SYS_FONT,
            fontWeight: 700,
            fontSize: 13,
            color: TEXT,
          }}
        >
          {name.slice(0, 1)}
        </div>
        <div style={{ fontSize: 12.5, color: MUTED, fontWeight: 500 }}>{name}</div>
      </div>
      <div
        style={{
          display: "flex",
          alignItems: "center",
          gap: 6,
          padding: "7px 8px 7px 12px",
          borderRadius: 999,
          background: CARD,
          border: `1px solid ${BORDER}`,
        }}
      >
        <span style={{ color: TEXT, fontSize: 10 }}>●</span>
        <span style={{ fontFamily: SYS_FONT, fontWeight: 700, fontSize: 13.5, color: TEXT }}>
          {fmt(balance)}
        </span>
        <span style={{ fontSize: 10.5, color: TEXT, fontWeight: 700, letterSpacing: 0.5 }}>GRAM</span>
        {onDeposit && (
          <button
            onClick={onDeposit}
            aria-label="Deposit"
            style={{
              marginLeft: 2, width: 20, height: 20, borderRadius: "50%", border: "none", cursor: "pointer",
              background: ACCENT2, color: "#1a1200", fontWeight: 900, fontSize: 13, lineHeight: 1,
              display: "flex", alignItems: "center", justifyContent: "center",
            }}
          >
            +
          </button>
        )}
      </div>
    </div>
  );
}

function BottomNav({ tab, setTab }) {
  const items = [
    { id: "games", label: "Games", icon: Icon.games },
    { id: "profile", label: "Profile", icon: Icon.profile },
  ];
  const active = tab === "profile" ? "profile" : "games";
  return (
    <div
      style={{
        position: "absolute",
        left: "50%",
        bottom: 14,
        transform: "translateX(-50%)",
        zIndex: 4,
        display: "flex",
        gap: 2,
        padding: 5,
        borderRadius: 999,
        background: "rgba(18,48,79,0.6)",
        backdropFilter: "blur(26px) saturate(200%)",
        WebkitBackdropFilter: "blur(26px) saturate(200%)",
        border: "1px solid rgba(255,255,255,0.08)",
        boxShadow: "0 10px 30px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.06)",
      }}
    >
      {items.map((it) => {
        const isActive = active === it.id;
        return (
          <button
            key={it.id}
            onClick={() => setTab(it.id)}
            style={{
              background: isActive
                ? "linear-gradient(180deg, rgba(41,169,245,0.35), rgba(41,169,245,0.12))"
                : "none",
              boxShadow: isActive ? "inset 0 1px 0 rgba(255,255,255,0.15)" : "none",
              border: "none",
              borderRadius: 999,
              padding: "9px 18px",
              display: "flex",
              alignItems: "center",
              gap: 7,
              cursor: "pointer",
              color: isActive ? "#ffffff" : MUTED,
            }}
          >
            <it.icon style={{ width: 18, height: 18 }} />
            <span style={{ fontSize: 12, fontWeight: 600, letterSpacing: 0.2 }}>{it.label}</span>
          </button>
        );
      })}
    </div>
  );
}

function Toast({ toast }) {
  if (!toast) return null;
  const color = toast.kind === "win" ? ACCENT2 : toast.kind === "lose" ? "#ff5d7a" : TEXT;
  return (
    <div
      key={toast.id}
      style={{
        position: "absolute",
        bottom: 78,
        left: "50%",
        transform: "translateX(-50%)",
        background: CARD,
        border: `1px solid ${color}55`,
        color,
        padding: "9px 16px",
        borderRadius: 999,
        fontSize: 12.5,
        fontWeight: 600,
        zIndex: 5,
        boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
        animation: "gram-toast-in 0.25s ease-out",
        whiteSpace: "nowrap",
      }}
    >
      {toast.msg}
      <style>{`@keyframes gram-toast-in{from{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%,0)}}`}</style>
    </div>
  );
}

/* ------------------------------ profile ------------------------------ */

function ProfileTab({ profile, history, authToken, pushToast, onBalanceDelta }) {
  const winRate = profile.wins + profile.losses > 0 ? Math.round((profile.wins / (profile.wins + profile.losses)) * 100) : 0;
  return (
    <div style={{ position: "relative", zIndex: 1, padding: "20px 18px 28px" }}>
      <div style={{ display: "flex", flexDirection: "column", alignItems: "center", marginBottom: 22 }}>
        <div
          style={{
            width: 74,
            height: 74,
            borderRadius: "50%",
            background: `radial-gradient(circle at 35% 30%, ${CARD}, ${BG})`,
            border: `2px solid ${BORDER}`,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            fontFamily: SYS_FONT,
            fontWeight: 900,
            fontSize: 26,
            color: "#ffffff",
            boxShadow: "none",
            marginBottom: 10,
          }}
        >
          {profile.name.slice(0, 1)}
        </div>
        <div style={{ fontFamily: SYS_FONT, fontWeight: 700, fontSize: 16 }}>{profile.name}</div>
        <div style={{ fontSize: 11.5, color: "#8b8d97", marginTop: 3 }}>
          member since {new Date(profile.createdAt).toLocaleDateString()}
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 18 }}>
        <StatCard label="Balance" value={fmt(profile.balance)} accent="#ffb703" icon={Icon.coin} />
        <StatCard label="Win rate" value={`${winRate}%`} accent="#29a9f5" icon={Icon.crown} />
        <StatCard label="Wagered" value={fmt(profile.wagered)} accent="#a855f7" icon={Icon.bolt} />
      </div>

      <WithdrawSection profile={profile} authToken={authToken} pushToast={pushToast} onBalanceDelta={onBalanceDelta} />

      <SectionLabel>Recent activity</SectionLabel>
      <div style={{ display: "flex", flexDirection: "column", gap: 8, marginTop: 8 }}>
        {history.length === 0 && (
          <EmptyNote>Nothing here yet — spin the daily wheel or start a duel.</EmptyNote>
        )}
        {history.map((h) => (
          <HistoryRow key={h.id} entry={h} />
        ))}
      </div>
    </div>
  );
}

/* --- withdraw: manual, admin-approved via bot ------------------------ */

function WithdrawSection({ profile, authToken, pushToast, onBalanceDelta }) {
  const [open, setOpen] = useState(false);
  const [amount, setAmount] = useState("");
  const [address, setAddress] = useState("");
  const [busy, setBusy] = useState(false);

  const amountNum = parseFloat(amount);
  const canSubmit = !busy && Number.isFinite(amountNum) && amountNum > 0 && amountNum <= profile.balance && address.trim().length >= 10;

  const submit = async () => {
    if (!authToken) {
      pushToast("Open this inside Telegram to withdraw.", "lose");
      return;
    }
    if (!canSubmit) return;
    setBusy(true);
    try {
      await apiPost("/withdraw/request", authToken, { amount: amountNum, walletAddress: address.trim() });
      onBalanceDelta(-amountNum); // deducted server-side immediately — mirror it locally
      pushToast(`Withdrawal of ${fmt(amountNum)} GRAM requested — pending admin approval`, "info");
      setAmount("");
      setAddress("");
      setOpen(false);
    } catch (e) {
      pushToast("Couldn't submit withdrawal. Try again shortly.", "lose");
    } finally {
      setBusy(false);
    }
  };

  return (
    <div style={{ background: CARD, border: `1px solid ${BORDER}`, borderRadius: 16, padding: 16, marginBottom: 18 }}>
      <div
        onClick={() => setOpen((v) => !v)}
        style={{ display: "flex", alignItems: "center", justifyContent: "space-between", cursor: "pointer" }}
      >
        <div style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 14.5, color: TEXT }}>Withdraw</div>
        <div style={{ fontFamily: SYS_FONT, fontSize: 11.5, color: MUTED }}>
          {open ? "close ▲" : "manual · admin-approved ▼"}
        </div>
      </div>

      {open && (
        <div style={{ marginTop: 14 }}>
          <div
            style={{
              display: "flex", alignItems: "center", gap: 10, background: BG, border: `1px solid ${BORDER}`,
              borderRadius: 12, padding: "10px 12px", marginBottom: 10,
            }}
          >
            <input
              type="number"
              inputMode="decimal"
              min="0"
              step="1"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
              placeholder="Amount"
              style={{ flex: 1, background: "transparent", border: "none", outline: "none", fontFamily: SYS_FONT, fontWeight: 700, fontSize: 15, color: TEXT }}
            />
            <span style={{ fontFamily: SYS_FONT, fontWeight: 700, fontSize: 12, color: MUTED }}>GRAM</span>
          </div>

          <input
            value={address}
            onChange={(e) => setAddress(e.target.value)}
            placeholder="Your TON wallet address"
            style={{
              width: "100%", boxSizing: "border-box", background: BG, border: `1px solid ${BORDER}`, borderRadius: 12,
              padding: "10px 12px", marginBottom: 12, fontFamily: "monospace", fontSize: 12.5, color: TEXT, outline: "none",
            }}
          />

          <div style={{ fontFamily: SYS_FONT, fontSize: 11.5, color: MUTED, marginBottom: 12, lineHeight: 1.5 }}>
            The amount is deducted from your balance right away. An admin reviews every request by hand —
            you'll get a message here once it's approved or rejected. If it's rejected, the amount is
            refunded to your balance automatically.
          </div>

          <button
            onClick={submit}
            disabled={!canSubmit}
            style={{
              width: "100%", border: "none", borderRadius: 12, padding: "12px 0",
              fontFamily: SYS_FONT, fontWeight: 800, fontSize: 14,
              background: canSubmit ? ACCENT : BORDER,
              color: canSubmit ? "#04121c" : MUTED,
              cursor: canSubmit ? "pointer" : "not-allowed",
            }}
          >
            {busy ? "Submitting…" : "Request withdrawal"}
          </button>
        </div>
      )}
    </div>
  );
}

function StatCard({ label, value, accent, icon: IconC }) {
  return (
    <div
      style={{
        background: CARD,
        border: `1px solid ${BORDER}`,
        borderRadius: 14,
        padding: "12px 10px",
        display: "flex",
        flexDirection: "column",
        gap: 6,
      }}
    >
      <IconC style={{ width: 15, height: 15, color: accent }} />
      <div style={{ fontFamily: SYS_FONT, fontWeight: 700, fontSize: 14 }}>{value}</div>
      <div style={{ fontSize: 10, color: "#8b8d97", fontWeight: 600 }}>{label}</div>
    </div>
  );
}

function SectionLabel({ children }) {
  return (
    <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1.2, color: "#8b8d97", textTransform: "uppercase" }}>
      {children}
    </div>
  );
}

function EmptyNote({ children }) {
  return (
    <div
      style={{
        border: `1px dashed ${BORDER}`,
        borderRadius: 12,
        padding: "16px 14px",
        fontSize: 12.5,
        color: "#8b8d97",
        textAlign: "center",
      }}
    >
      {children}
    </div>
  );
}

function HistoryRow({ entry }) {
  const positive = entry.delta >= 0;
  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        background: CARD,
        border: `1px solid ${BORDER}`,
        borderRadius: 12,
        padding: "10px 12px",
      }}
    >
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <div
          style={{
            width: 30,
            height: 30,
            borderRadius: 9,
            background: entry.type === "pvp" ? "rgba(168,85,247,0.15)" : "rgba(41,169,245,0.12)",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}
        >
          {entry.type === "pvp" ? (
            <Icon.swords style={{ width: 14, height: 14, color: "#a855f7" }} />
          ) : (
            <Icon.bolt style={{ width: 14, height: 14, color: "#29a9f5" }} />
          )}
        </div>
        <div>
          <div style={{ fontSize: 12.5, fontWeight: 600 }}>{entry.label}</div>
          <div style={{ fontSize: 10.5, color: "#8b8d97" }}>
            {new Date(entry.at).toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" })}
          </div>
        </div>
      </div>
      <div style={{ fontFamily: SYS_FONT, fontWeight: 700, fontSize: 12.5, color: positive ? ACCENT2 : "#ff5d7a" }}>
        {positive ? "+" : ""}
        {fmt(entry.delta)}
      </div>
    </div>
  );
}

/* ------------------------------ games hub ------------------------------ */

function GamesTab({ onOpenSpin, onOpenPvp, profile }) {
  const cooldownLeft = Math.max(0, profile.lastFreeSpin + DAILY_COOLDOWN_MS - Date.now());
  const canFree = cooldownLeft <= 0;

  return (
    <div style={{ position: "relative", zIndex: 1, padding: "18px 18px 28px" }}>
      <SectionLabel>Casino floor</SectionLabel>
      <div style={{ marginTop: 12, display: "flex", flexDirection: "column", gap: 14 }}>
        <GameCard
          title="Daily Free Spin"
          subtitle={canFree ? "Ready — spin the wheel, on the house" : `Next spin in ${formatCountdown(cooldownLeft)}`}
          tag={canFree ? "FREE" : "COOLDOWN"}
          gradient="linear-gradient(135deg, #3a3d47, #1b1d24)"
          icon={Icon.bolt}
          onClick={onOpenSpin}
        />
        <GameCard
          title="PvP Duel Spin"
          subtitle="Wager GRAM against another player — biggest stake, biggest odds"
          tag="LIVE"
          gradient="linear-gradient(135deg, #a855f7, #5b21b6)"
          icon={Icon.swords}
          onClick={onOpenPvp}
        />
      </div>
    </div>
  );
}

function GameCard({ title, subtitle, tag, gradient, icon: IconC, onClick }) {
  return (
    <button
      onClick={onClick}
      style={{
        textAlign: "left",
        cursor: "pointer",
        border: `1px solid ${BORDER}`,
        background: CARD,
        borderRadius: 18,
        padding: 16,
        display: "flex",
        alignItems: "center",
        gap: 14,
        position: "relative",
        overflow: "hidden",
        boxShadow: "0 8px 20px rgba(0,0,0,0.25)",
      }}
    >
      <div
        style={{
          width: 50,
          height: 50,
          borderRadius: 14,
          background: gradient,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          flexShrink: 0,
          boxShadow: "0 6px 16px rgba(0,0,0,0.35)",
        }}
      >
        <IconC style={{ width: 22, height: 22, color: "#fff" }} />
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <div style={{ fontFamily: SYS_FONT, fontWeight: 700, fontSize: 14, color: TEXT }}>{title}</div>
          <span
            style={{
              fontSize: 9,
              fontWeight: 800,
              letterSpacing: 0.5,
              color: ACCENT2,
              border: `1px solid ${ACCENT2}55`,
              borderRadius: 999,
              padding: "2px 7px",
            }}
          >
            {tag}
          </span>
        </div>
        <div style={{ fontSize: 11.5, color: MUTED, marginTop: 4, lineHeight: 1.4 }}>{subtitle}</div>
      </div>
    </button>
  );
}

function formatCountdown(ms) {
  const totalSec = Math.ceil(ms / 1000);
  const h = Math.floor(totalSec / 3600);
  const m = Math.floor((totalSec % 3600) / 60);
  const s = totalSec % 60;
  return `${h}h ${m}m ${s}s`;
}

/* ------------------------------ wheel visual ------------------------------ */

function Wheel({ rotation, spinning, size = 240 }) {
  const n = WHEEL_SEGMENTS.length;
  const segAngle = 360 / n;
  const r = size / 2;

  return (
    <div style={{ position: "relative", width: size, height: size }}>
      <div
        style={{
          position: "absolute",
          top: -6,
          left: "50%",
          transform: "translateX(-50%)",
          width: 0,
          height: 0,
          borderLeft: "9px solid transparent",
          borderRight: "9px solid transparent",
          borderTop: "16px solid #ffb703",
          zIndex: 3,
          filter: "drop-shadow(0 0 6px rgba(255,165,61,0.8))",
        }}
      />
      <div
        style={{
          width: size,
          height: size,
          borderRadius: "50%",
          position: "relative",
          transition: spinning ? "transform 3.2s cubic-bezier(0.12,0.72,0.15,1)" : "none",
          transform: `rotate(${rotation}deg)`,
          boxShadow: "0 0 0 3px rgba(41,169,245,0.4), 0 0 40px rgba(41,169,245,0.25)",
        }}
      >
        <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
          {WHEEL_SEGMENTS.map((seg, i) => {
            const start = (i * segAngle - 90) * (Math.PI / 180);
            const end = ((i + 1) * segAngle - 90) * (Math.PI / 180);
            const x1 = r + r * Math.cos(start);
            const y1 = r + r * Math.sin(start);
            const x2 = r + r * Math.cos(end);
            const y2 = r + r * Math.sin(end);
            const largeArc = segAngle > 180 ? 1 : 0;
            const mid = (start + end) / 2;
            const lx = r + r * 0.62 * Math.cos(mid);
            const ly = r + r * 0.62 * Math.sin(mid);
            return (
              <g key={i}>
                <path
                  d={`M${r},${r} L${x1},${y1} A${r},${r} 0 ${largeArc} 1 ${x2},${y2} Z`}
                  fill={seg.color}
                  stroke="#000000"
                  strokeWidth="1.5"
                />
                <text
                  x={lx}
                  y={ly}
                  fill="#ffffff"
                  fontSize="13"
                  fontFamily={SYS_FONT}
                  fontWeight="700"
                  textAnchor="middle"
                  dominantBaseline="middle"
                  transform={`rotate(${(mid * 180) / Math.PI + 90}, ${lx}, ${ly})`}
                >
                  {seg.label}
                </text>
              </g>
            );
          })}
          <circle cx={r} cy={r} r={r - 2} fill="none" stroke="rgba(41,169,245,0.5)" strokeWidth="2" />
        </svg>
      </div>
      <div
        style={{
          position: "absolute",
          top: "50%",
          left: "50%",
          transform: "translate(-50%,-50%)",
          width: 46,
          height: 46,
          borderRadius: "50%",
          background: "radial-gradient(circle, #23252c, #000000)",
          border: "2px solid rgba(41,169,245,0.6)",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          zIndex: 2,
          boxShadow: "0 0 20px rgba(41,169,245,0.4)",
        }}
      >
        <Icon.coin style={{ width: 20, height: 20, color: "#ffb703" }} />
      </div>
    </div>
  );
}

/* ------------------------------ daily spin ------------------------------ */

function DailySpinTab({ profile, commit, pushToast, onBack }) {
  const [rotation, setRotation] = useState(0);
  const [spinning, setSpinning] = useState(false);
  const [resultSeg, setResultSeg] = useState(null);
  const timeoutRef = useRef(null);

  useEffect(() => () => clearTimeout(timeoutRef.current), []);

  const cooldownLeft = Math.max(0, profile.lastFreeSpin + DAILY_COOLDOWN_MS - Date.now());
  const [tick, setTick] = useState(0);
  useEffect(() => {
    const t = setInterval(() => setTick((x) => x + 1), 1000);
    return () => clearInterval(t);
  }, []);
  const liveCooldown = Math.max(0, profile.lastFreeSpin + DAILY_COOLDOWN_MS - Date.now());
  const canSpin = liveCooldown <= 0 && !spinning;

  const STAKE = 20; // notional stake used purely to compute the free spin's prize

  const doSpin = () => {
    if (!canSpin) return;
    setSpinning(true);
    setResultSeg(null);

    const n = WHEEL_SEGMENTS.length;
    const segAngle = 360 / n;
    const targetIndex = Math.floor(Math.random() * n);
    const spins = 5 + Math.floor(Math.random() * 3);
    const targetRotation =
      rotation + spins * 360 + (360 - (targetIndex * segAngle + segAngle / 2)) + (Math.random() * 10 - 5);

    requestAnimationFrame(() => {
      requestAnimationFrame(() => {
        setRotation(targetRotation);
      });
    });

    timeoutRef.current = setTimeout(() => {
      const seg = WHEEL_SEGMENTS[targetIndex];
      const prize = fmt(STAKE * seg.mult);
      const nextProfile = {
        ...profile,
        balance: fmt(profile.balance + prize),
        lastFreeSpin: Date.now(),
        wins: seg.mult > 1 ? profile.wins + 1 : profile.wins,
        losses: seg.mult <= 1 ? profile.losses + (seg.mult === 0 ? 1 : 0) : profile.losses,
      };
      commit(nextProfile, {
        id: uid(),
        type: "daily",
        label: seg.mult === 0 ? "Daily spin — bust" : `Daily spin — ${seg.label}`,
        delta: prize,
        at: Date.now(),
      });
      setResultSeg(seg);
      pushToast(seg.mult === 0 ? "No luck this time 💨" : `Won ${prize} GRAM! 🎉`, seg.mult === 0 ? "lose" : "win");
      setSpinning(false);
    }, 3250);
  };

  return (
    <div style={{ position: "relative", zIndex: 1, padding: "16px 18px 28px" }}>
      <BackButton onClick={onBack} />
      <div style={{ textAlign: "center", marginTop: 6, marginBottom: 18 }}>
        <div style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 19, background: "linear-gradient(90deg,#29a9f5,#a855f7)", WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>
          Daily Free Spin
        </div>
        <div style={{ fontSize: 12, color: "#8b8d97", marginTop: 4 }}>One free spin every 24 hours. No stake required.</div>
      </div>

      <div style={{ display: "flex", justifyContent: "center", margin: "10px 0 22px" }}>
        <Wheel rotation={rotation} spinning={spinning} />
      </div>

      {resultSeg && !spinning && (
        <div style={{ textAlign: "center", marginBottom: 16, fontSize: 13, color: resultSeg.mult > 0 ? "#29a9f5" : "#8b8d97" }}>
          Landed on <b style={{ fontFamily: SYS_FONT }}>{resultSeg.label}</b>
        </div>
      )}

      <PrimaryButton onClick={doSpin} disabled={!canSpin} glow="#29a9f5">
        {spinning ? "Spinning…" : canSpin ? "Spin now — free" : `Next free spin in ${formatCountdown(liveCooldown)}`}
      </PrimaryButton>

      <div style={{ marginTop: 22 }}>
        <SectionLabel>Wheel odds</SectionLabel>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginTop: 10 }}>
          {WHEEL_SEGMENTS.map((s, i) => (
            <div
              key={i}
              style={{
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                background: CARD,
                border: `1px solid ${BORDER}`,
                borderRadius: 10,
                padding: "7px 10px",
                fontSize: 11.5,
              }}
            >
              <span style={{ color: "#8b8d97" }}>Segment {i + 1}</span>
              <span style={{ fontFamily: SYS_FONT, fontWeight: 700, color: s.mult === 0 ? "#8b8d97" : "#ffffff" }}>{s.label}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ------------------------------ pvp spin ------------------------------ */

const PLAYER_COLORS = ["#29a9f5", "#a855f7", "#ffb703", "#4CFFB0", "#FF5D7A", "#FFD84C"];

function JackpotWheel({ participants, rotation, spinning, size = 240 }) {
  const r = size / 2;
  const total = participants.reduce((s, p) => s + p.stake, 0);

  let cursor = 0;
  const arcs = participants.map((p) => {
    const frac = p.stake / total;
    const startAngle = cursor;
    const endAngle = cursor + frac * 360;
    cursor = endAngle;
    return { ...p, startAngle, endAngle };
  });

  const polar = (angleDeg) => {
    const rad = ((angleDeg - 90) * Math.PI) / 180;
    return { x: r + r * Math.cos(rad), y: r + r * Math.sin(rad) };
  };

  return (
    <div style={{ position: "relative", width: size, height: size }}>
      <div
        style={{
          position: "absolute",
          top: -6,
          left: "50%",
          transform: "translateX(-50%)",
          width: 0,
          height: 0,
          borderLeft: "9px solid transparent",
          borderRight: "9px solid transparent",
          borderTop: "16px solid #ffffff",
          zIndex: 3,
          filter: "drop-shadow(0 0 6px rgba(234,246,255,0.8))",
        }}
      />
      <div
        style={{
          width: size,
          height: size,
          borderRadius: "50%",
          position: "relative",
          transition: spinning ? "transform 3.2s cubic-bezier(0.12,0.72,0.15,1)" : "none",
          transform: `rotate(${rotation}deg)`,
          boxShadow: "0 0 0 3px rgba(168,85,247,0.4), 0 0 40px rgba(168,85,247,0.22)",
        }}
      >
        <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
          {arcs.map((a, i) => {
            const p1 = polar(a.startAngle);
            const p2 = polar(a.endAngle);
            const largeArc = a.endAngle - a.startAngle > 180 ? 1 : 0;
            const mid = (a.startAngle + a.endAngle) / 2;
            const lp = polar(mid);
            const lx = r + (lp.x - r) * 0.62;
            const ly = r + (lp.y - r) * 0.62;
            const pct = Math.round((a.stake / total) * 100);
            return (
              <g key={i}>
                <path
                  d={`M${r},${r} L${p1.x},${p1.y} A${r},${r} 0 ${largeArc} 1 ${p2.x},${p2.y} Z`}
                  fill={a.color}
                  stroke="#000000"
                  strokeWidth="1.5"
                  opacity={a.isYou ? 1 : 0.88}
                />
                {pct >= 8 && (
                  <text
                    x={lx}
                    y={ly}
                    fill="#000000"
                    fontSize="12"
                    fontFamily={SYS_FONT}
                    fontWeight="800"
                    textAnchor="middle"
                    dominantBaseline="middle"
                    transform={`rotate(${mid}, ${lx}, ${ly})`}
                  >
                    {pct}%
                  </text>
                )}
              </g>
            );
          })}
          <circle cx={r} cy={r} r={r - 2} fill="none" stroke="rgba(168,85,247,0.5)" strokeWidth="2" />
        </svg>
      </div>
      <div
        style={{
          position: "absolute",
          top: "50%",
          left: "50%",
          transform: "translate(-50%,-50%)",
          width: 46,
          height: 46,
          borderRadius: "50%",
          background: "radial-gradient(circle, #23252c, #000000)",
          border: "2px solid rgba(168,85,247,0.6)",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          zIndex: 2,
          boxShadow: "0 0 20px rgba(168,85,247,0.4)",
        }}
      >
        <Icon.coin style={{ width: 20, height: 20, color: "#ffb703" }} />
      </div>
    </div>
  );
}

function PlayerCard({ player, pct }) {
  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        padding: "9px 12px",
        borderRadius: 12,
        background: player.isYou ? `${player.color}14` : CARD,
        border: `1px solid ${player.isYou ? player.color + "55" : BORDER}`,
      }}
    >
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <div
          style={{
            width: 28,
            height: 28,
            borderRadius: "50%",
            background: `radial-gradient(circle at 35% 30%, ${player.color}, #000000)`,
            border: `1.5px solid ${player.color}`,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            fontWeight: 800,
            fontSize: 11.5,
            color: "#000000",
            flexShrink: 0,
          }}
        >
          {player.name.slice(0, 1)}
        </div>
        <div>
          <div style={{ fontSize: 12.5, fontWeight: player.isYou ? 700 : 500, color: player.isYou ? "#ffffff" : "#8b8d97" }}>
            {player.name}
          </div>
          <div style={{ fontSize: 10, color: "#8b8d97", fontWeight: 600 }}>{player.stake} GRAM staked</div>
        </div>
      </div>
      <div
        style={{
          fontWeight: 800,
          fontSize: 13,
          color: player.color,
          padding: "4px 9px",
          borderRadius: 999,
          background: `${player.color}1a`,
          border: `1px solid ${player.color}44`,
        }}
      >
        {pct}%
      </div>
    </div>
  );
}

const LOBBY_SECONDS = 5;

function PvpSpinTab({ profile, commit, pushToast, onBack }) {
  const [stage, setStage] = useState("setup"); // setup | lobby | result
  const [stake, setStake] = useState(50);
  const [participants, setParticipants] = useState([]);
  const [countdown, setCountdown] = useState(LOBBY_SECONDS);
  const [rotation, setRotation] = useState(0);
  const [spinning, setSpinning] = useState(false);
  const [outcome, setOutcome] = useState(null); // { win, winnerName, delta }
  const timeoutRef = useRef(null);
  const countdownIntervalRef = useRef(null);
  const botTimeoutsRef = useRef([]);
  const participantsRef = useRef([]);
  const rotationRef = useRef(0);

  useEffect(() => {
    participantsRef.current = participants;
  }, [participants]);
  useEffect(() => {
    rotationRef.current = rotation;
  }, [rotation]);

  // fixed sample opponents used only for the setup-screen preview, so the wheel
  // doesn't jump around while the user is just adjusting their stake
  const [sampleBots] = useState(() =>
    [1, 2].map((i) => ({
      name: BOT_NAMES[Math.floor(Math.random() * BOT_NAMES.length)],
      stake: 30 + Math.floor(Math.random() * 90),
      color: PLAYER_COLORS[i % PLAYER_COLORS.length],
      isYou: false,
    }))
  );

  const clearAllTimers = () => {
    clearTimeout(timeoutRef.current);
    clearInterval(countdownIntervalRef.current);
    botTimeoutsRef.current.forEach(clearTimeout);
    botTimeoutsRef.current = [];
  };

  useEffect(() => clearAllTimers, []);

  const maxStake = Math.max(10, Math.floor(profile.balance));
  const presets = [25, 50, 100, 200].filter((v) => v <= maxStake);

  const startSpin = () => {
    const currentParticipants = participantsRef.current;
    if (currentParticipants.length === 0) return;
    setSpinning(true);

    const total = currentParticipants.reduce((s, p) => s + p.stake, 0);
    let cursor = 0;
    const arcs = currentParticipants.map((p) => {
      const frac = p.stake / total;
      const startAngle = cursor;
      const endAngle = cursor + frac * 360;
      cursor = endAngle;
      return { ...p, startAngle, endAngle };
    });

    const roll = Math.random() * total;
    let acc = 0;
    let winner = arcs[0];
    for (const a of arcs) {
      acc += a.stake;
      if (roll <= acc) {
        winner = a;
        break;
      }
    }

    const landingAngle = winner.startAngle + Math.random() * (winner.endAngle - winner.startAngle);
    const spins = 5 + Math.floor(Math.random() * 3);
    const targetRotation = rotationRef.current + spins * 360 + (360 - landingAngle);
    requestAnimationFrame(() => {
      requestAnimationFrame(() => {
        setRotation(targetRotation);
      });
    });

    timeoutRef.current = setTimeout(() => {
      const you = currentParticipants.find((p) => p.isYou);
      const isWin = winner.isYou;
      const delta = isWin ? fmt(total - you.stake) : fmt(-you.stake);
      const nextProfile = {
        ...profile,
        balance: fmt(profile.balance + delta),
        wins: isWin ? profile.wins + 1 : profile.wins,
        losses: isWin ? profile.losses : profile.losses + 1,
        wagered: fmt(profile.wagered + you.stake),
      };
      commit(nextProfile, {
        id: uid(),
        type: "pvp",
        label: isWin ? "PvP spin — won the pot" : `PvP spin — ${winner.name} took the pot`,
        delta,
        at: Date.now(),
      });
      setOutcome({ win: isWin, winnerName: winner.name, delta });
      pushToast(isWin ? `You won the pot: +${delta} GRAM 🏆` : `${winner.name} took the pot: ${delta} GRAM`, isWin ? "win" : "lose");
      setSpinning(false);
      setStage("result");
    }, 3250);
  };

  const joinPot = () => {
    if (stake < 10 || stake > profile.balance) {
      pushToast("Stake must be between 10 and your balance.", "lose");
      return;
    }

    const you = { name: "You", stake, color: PLAYER_COLORS[0], isYou: true };
    setParticipants([you]);
    setOutcome(null);
    setRotation(0);
    setCountdown(LOBBY_SECONDS);
    setStage("lobby");

    const botCount = 1 + Math.floor(Math.random() * 3); // 1–3 other players join during the window
    const shuffledNames = [...BOT_NAMES].sort(() => Math.random() - 0.5).slice(0, botCount);
    botTimeoutsRef.current = shuffledNames.map((name, i) => {
      const delay = 500 + Math.random() * (LOBBY_SECONDS * 1000 - 900);
      return setTimeout(() => {
        setParticipants((prev) => [
          ...prev,
          {
            name,
            stake: Math.max(10, Math.round(stake * (0.4 + Math.random() * 1.4))),
            color: PLAYER_COLORS[prev.length % PLAYER_COLORS.length],
            isYou: false,
          },
        ]);
      }, delay);
    });

    let secondsLeft = LOBBY_SECONDS;
    countdownIntervalRef.current = setInterval(() => {
      secondsLeft -= 1;
      setCountdown(Math.max(0, secondsLeft));
      if (secondsLeft <= 0) {
        clearInterval(countdownIntervalRef.current);
        botTimeoutsRef.current.forEach(clearTimeout);
        startSpin();
      }
    }, 1000);
  };

  const addCoins = (amount) => {
    setParticipants((prev) => {
      const idx = prev.findIndex((p) => p.isYou);
      if (idx === -1) return prev;
      const you = prev[idx];
      const newStake = Math.min(profile.balance, you.stake + amount);
      if (newStake === you.stake) return prev;
      const updated = [...prev];
      updated[idx] = { ...you, stake: newStake };
      return updated;
    });
  };

  const resetDuel = () => {
    clearAllTimers();
    setStage("setup");
    setParticipants([]);
    setOutcome(null);
    setRotation(0);
    setCountdown(LOBBY_SECONDS);
  };

  const previewParticipants = [{ name: "You", stake, color: PLAYER_COLORS[0], isYou: true }, ...sampleBots];
  const displayParticipants = stage === "setup" ? previewParticipants : participants;
  const total = displayParticipants.reduce((s, p) => s + p.stake, 0);

  return (
    <div style={{ position: "relative", zIndex: 1, padding: "16px 18px 28px" }}>
      <BackButton onClick={onBack} />
      <div style={{ textAlign: "center", marginTop: 6, marginBottom: 18 }}>
        <div style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 19, background: "linear-gradient(90deg,#a855f7,#ffb703)", WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>
          PvP Spin
        </div>
      </div>

      {stage === "lobby" && !spinning && (
        <div style={{ textAlign: "center", marginBottom: 14 }}>
          <div
            style={{
              display: "inline-flex",
              alignItems: "center",
              gap: 8,
              padding: "8px 16px",
              borderRadius: 999,
              background: "rgba(41,169,245,0.1)",
              border: "1px solid rgba(41,169,245,0.35)",
            }}
          >
            <span style={{ width: 7, height: 7, borderRadius: "50%", background: "#29a9f5", boxShadow: "0 0 8px #29a9f5" }} className="gram-livedot" />
            <span style={{ fontSize: 12, color: "#8b8d97", fontWeight: 600 }}>Pot closes in</span>
            <span style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 15, color: "#29a9f5" }}>{countdown}s</span>
          </div>
          <style>{`.gram-livedot{animation:gram-live-pulse 1s ease-in-out infinite}@keyframes gram-live-pulse{0%,100%{opacity:.4}50%{opacity:1}}`}</style>
        </div>
      )}

      <div style={{ display: "flex", justifyContent: "center", marginBottom: 6 }}>
        <JackpotWheel participants={displayParticipants} rotation={rotation} spinning={spinning} size={280} />
      </div>

      {stage === "setup" && (
        <div style={{ textAlign: "center", fontSize: 10.5, color: "#8b8d97", marginBottom: 16 }}>
          your arc grows as your stake grows — this is just a preview, no GRAM is spent yet
        </div>
      )}

      {stage === "lobby" && !spinning && (
        <div style={{ display: "flex", justifyContent: "center", gap: 8, margin: "16px 0" }}>
          {[10, 25, 50].map((amt) => (
            <button
              key={amt}
              onClick={() => addCoins(amt)}
              disabled={profile.balance <= 0}
              style={{
                padding: "7px 14px",
                borderRadius: 999,
                border: "1px solid rgba(255,183,3,0.4)",
                background: "rgba(255,183,3,0.1)",
                color: "#ffb703",
                fontSize: 12,
                fontWeight: 700,
                cursor: "pointer",
              }}
            >
              +{amt} GRAM
            </button>
          ))}
        </div>
      )}

      {stage !== "setup" && (
        <div style={{ display: "flex", flexDirection: "column", gap: 8, margin: "16px 0 10px" }}>
          {displayParticipants.map((p, i) => (
            <PlayerCard key={i} player={p} pct={Math.round((p.stake / total) * 100)} />
          ))}
        </div>
      )}

      {stage !== "setup" && (
        <div style={{ textAlign: "center", fontSize: 11.5, color: "#8b8d97", marginBottom: 16 }}>
          Pot: <b style={{ color: "#ffb703", fontFamily: SYS_FONT }}>{fmt(total)} GRAM</b>
        </div>
      )}

      {stage === "lobby" && !spinning && (
        <div style={{ textAlign: "center", fontSize: 11, color: "#8b8d97", marginBottom: 18 }}>
          other players can still join — the wheel spins automatically when the timer hits 0
        </div>
      )}

      {stage === "lobby" && spinning && (
        <div style={{ textAlign: "center", fontSize: 13, color: "#29a9f5", fontWeight: 700, marginBottom: 18 }}>Spinning…</div>
      )}

      {stage === "setup" && (
        <div>
          <div style={{ marginBottom: 18 }}>
            <PrimaryButton onClick={joinPot} glow="#a855f7">
              Join pot
            </PrimaryButton>
          </div>

          <SectionLabel>Your stake</SectionLabel>
          <div
            style={{
              marginTop: 10,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              gap: 14,
              background: CARD,
              border: `1px solid ${BORDER}`,
              borderRadius: 16,
              padding: "18px 14px",
            }}
          >
            <StepButton onClick={() => setStake((s) => Math.max(10, s - 10))}>–</StepButton>
            <div style={{ textAlign: "center" }}>
              <div style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 26 }}>{stake}</div>
              <div style={{ fontSize: 10, color: "#8b8d97", fontWeight: 700, letterSpacing: 0.5 }}>GRAM</div>
            </div>
            <StepButton onClick={() => setStake((s) => Math.min(maxStake, s + 10))}>+</StepButton>
          </div>

          <div style={{ display: "flex", gap: 8, marginTop: 12, marginBottom: 20 }}>
            {presets.map((p) => (
              <button
                key={p}
                onClick={() => setStake(p)}
                style={{
                  flex: 1,
                  padding: "8px 0",
                  borderRadius: 10,
                  border: `1px solid ${stake === p ? "#29a9f5" : "rgba(41,169,245,0.18)"}`,
                  background: stake === p ? "rgba(41,169,245,0.12)" : "transparent",
                  color: stake === p ? "#29a9f5" : "#8b8d97",
                  fontSize: 12,
                  fontWeight: 700,
                  cursor: "pointer",
                }}
              >
                {p}
              </button>
            ))}
          </div>

          <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 18 }}>
            {displayParticipants.map((p, i) => {
              return <PlayerCard key={i} player={p} pct={Math.round((p.stake / total) * 100)} />;
            })}
          </div>
        </div>
      )}

      {stage === "result" && outcome && (
        <div>
          <div
            style={{
              textAlign: "center",
              padding: "14px 0",
              marginBottom: 14,
              borderRadius: 14,
              background: outcome.win ? "rgba(168,85,247,0.08)" : "rgba(255,93,122,0.08)",
              border: `1px solid ${outcome.win ? "rgba(168,85,247,0.35)" : "rgba(255,93,122,0.3)"}`,
            }}
          >
            <div style={{ fontFamily: SYS_FONT, fontWeight: 800, fontSize: 16, color: outcome.win ? "#a855f7" : "#ff5d7a" }}>
              {outcome.win ? "You took the pot 🏆" : `${outcome.winnerName} took the pot`}
            </div>
            <div style={{ fontSize: 12, color: "#8b8d97", marginTop: 4 }}>
              {outcome.win ? "+" : ""}
              {outcome.delta} GRAM
            </div>
          </div>
          <PrimaryButton onClick={resetDuel} glow="#a855f7">
            New spin
          </PrimaryButton>
        </div>
      )}
    </div>
  );
}

function StepButton({ children, onClick }) {
  return (
    <button
      onClick={onClick}
      style={{
        width: 38,
        height: 38,
        borderRadius: "50%",
        border: "1px solid rgba(41,169,245,0.3)",
        background: CARD,
        color: "#29a9f5",
        fontSize: 18,
        fontWeight: 700,
        cursor: "pointer",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      {children}
    </button>
  );
}

function PrimaryButton({ children, onClick, disabled, glow = "#29a9f5" }) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      style={{
        width: "100%",
        padding: "15px 0",
        borderRadius: 999,
        border: "none",
        cursor: disabled ? "not-allowed" : "pointer",
        fontFamily: SYS_FONT,
        fontWeight: 700,
        fontSize: 14,
        letterSpacing: 0.2,
        color: disabled ? "#8b8d97" : "#ffffff",
        background: disabled ? "rgba(255,255,255,0.06)" : glow,
        boxShadow: disabled ? "none" : `0 6px 20px ${glow}4d`,
        transition: "transform 0.15s ease",
      }}
      onMouseDown={(e) => !disabled && (e.currentTarget.style.transform = "scale(0.97)")}
      onMouseUp={(e) => (e.currentTarget.style.transform = "scale(1)")}
    >
      {children}
    </button>
  );
}

function BackButton({ onClick }) {
  return (
    <button
      onClick={onClick}
      style={{
        background: "none",
        border: "none",
        color: "#29a9f5",
        fontSize: 12.5,
        fontWeight: 600,
        display: "flex",
        alignItems: "center",
        gap: 4,
        cursor: "pointer",
        padding: 0,
      }}
    >
      ← Games
    </button>
  );
}
