/* ============================================================
   BridgeOS — Leaderboard & friend profiles
   Supports both local demo friends and real Supabase users.
   ============================================================ */
function Avatar({ profile, size }) {
  const s = size || 40;
  const hue = (profile.meta.name.charCodeAt(0) * 37) % 360;
  if (profile.meta.avatar) return <img className="avatar" src={profile.meta.avatar} style={{ width: s, height: s }} alt="" />;
  return <div className="avatar avatar-letter" style={{ width: s, height: s, fontSize: s * 0.42, background: `oklch(0.4 0.12 ${hue})` }}>{profile.meta.name[0]}</div>;
}

// Compute stats for a profile — handles both full (demo) and snapshot (real) profiles
function profileStats(profile, today) {
  const P = window.PP;
  if (profile._isRealUser) {
    return {
      power: profile._power || 0,
      level: profile._level || 1,
      scores: profile._scores || {},
      streak: profile._streak || 0,
    };
  }
  return {
    power: P.power(profile, today),
    level: P.profileLevel(profile).level,
    scores: P.decayedScores(profile, today),
    streak: P.streak(profile, today),
  };
}

function Leaderboard({ state, today, onMessage, authUser, onRefreshFriends }) {
  const P = window.PP;
  const [mode, setMode] = useState("week");
  const [detail, setDetail] = useState(null);
  const [info, setInfo] = useState(false);
  const [showAddFriend, setShowAddFriend] = useState(false);
  const [lbTab, setLbTab] = useState("ranks"); // "ranks" | "prs"

  const all = [state.me, ...state.friends];

  // Build leaderboard rows handling both profile types
  const rows = all.map((p) => {
    const stats = profileStats(p, today);
    return {
      id: p.id,
      profile: p,
      isMe: p.id === "me",
      power: stats.power,
      level: stats.level,
      scores: stats.scores,
      streak: stats.streak,
    };
  });
  rows.sort((a, b) => b.power - a.power);
  rows.forEach((r, i) => (r.rank = i + 1));

  // Category leaders — for real users use snapshot scores, for demo use windowTotals
  const catLeader = {};
  P.CAT_ORDER.forEach((c) => {
    let best = null, bestV = -1;
    all.forEach((p) => {
      let v;
      if (p._isRealUser) {
        v = (p._scores && p._scores[c]) ? P.catLevel(p._scores[c]).level : 0;
      } else if (p.id === "me") {
        v = P.catLevel(P.decayedScores(p, today)[c]).level;
      } else {
        v = P.windowTotals(p, today, mode)[c];
      }
      if (v > bestV) { bestV = v; best = p; }
    });
    catLeader[c] = { profile: best, value: bestV };
  });

  function windowVal(profile, cat) {
    if (profile._isRealUser) {
      const score = (profile._scores && profile._scores[cat]) || 0;
      return P.catLevel(score).level;
    }
    if (profile.id === "me") {
      return P.catLevel(P.decayedScores(profile, today)[cat]).level;
    }
    return P.windowTotals(profile, today, mode)[cat];
  }

  function windowLabel(profile, cat) {
    if (profile._isRealUser || profile.id === "me") return "Lv " + windowVal(profile, cat);
    const v = P.windowTotals(profile, today, mode)[cat];
    return v >= 1000 ? (v / 1000).toFixed(1) + "k" : Math.round(v);
  }

  return (
    <div className="lb">
      <div className="ql-head">
        <div>
          <div className="ql-date">Leaderboard</div>
          <div className="ql-quote">Ranked by live Power — your decayed attribute levels. Keep logging or you slip. <button className="link-btn" onClick={() => setInfo(!info)}>What is Power?</button></div>
        </div>
        <div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
          {authUser && (
            <button className="btn btn-sm btn-accent" onClick={() => setShowAddFriend(true)}>+ Add friend</button>
          )}
          {authUser && onRefreshFriends && (
            <button className="btn btn-sm" onClick={onRefreshFriends} title="Refresh friend list">↻</button>
          )}
          <Seg options={[{ value: "ranks", label: "Rankings" }, { value: "prs", label: "🏋️ PRs" }]} value={lbTab} onChange={setLbTab} />
          {lbTab === "ranks" && <Seg options={[{ value: "day", label: "Day" }, { value: "week", label: "Week" }, { value: "month", label: "Month" }]} value={mode} onChange={setMode} />}
        </div>
      </div>

      {lbTab === "prs" && <GymPRs authUser={authUser} state={state} />}

      {lbTab === "ranks" && info && (
        <Card title="Power vs. Level — momentum, explained">
          <div className="power-explain">
            <div className="pe-pair">
              <div className="pe-badge"><span className="mono pe-badge-n">⚡</span><span className="pe-badge-l">POWER</span></div>
              <div><b>Your momentum.</b> Every minute, rep, and dollar you log starts strong and then <b>decays</b> a little each day. Power is the sum of your six attribute levels computed from those <i>decayed</i> scores — so it <b>falls if you stop</b> and climbs as you stack days. The leaderboard ranks on this.</div>
            </div>
            <div className="pe-pair">
              <div className="pe-badge alt"><span className="mono pe-badge-n">Lv</span><span className="pe-badge-l">LEVEL</span></div>
              <div><b>Your résumé.</b> Built from everything you've <i>ever</i> logged (weighted). It never decays and never goes down — the slow, permanent climb.</div>
            </div>
            <div className="pe-decay">
              <div className="dd-section-label">HOW FAST EACH STAT FADES (half-life)</div>
              <div className="pe-decay-grid">
                {P.CAT_ORDER.map((c) => (
                  <div className="pe-decay-cell" key={c} style={{ "--ch": `oklch(0.82 0.15 ${P.CATS[c].hue})` }}>
                    <span className="pe-decay-key">{c}</span>
                    <span className="pe-decay-half mono">{P.CATS[c].half}d</span>
                    <span className="pe-decay-name">{P.CATS[c].name}</span>
                  </div>
                ))}
              </div>
              <div className="dim mono pe-decay-note">Discipline rots fastest — slack a week and it halves. Wealth lingers longest.</div>
            </div>
          </div>
        </Card>
      )}

      {/* category leaders — ranks tab only */}
      {lbTab === "ranks" && <Card title={`Category leaders · this ${mode}`}>
        <div className="cat-leaders">
          {P.CAT_ORDER.map((c) => {
            const L = catLeader[c];
            return (
              <div className="cat-leader" key={c} style={{ "--ch": `oklch(0.82 0.15 ${P.CATS[c].hue})` }}>
                <div className="cat-leader-key">{c}</div>
                {L.profile && L.value > 0 ? (
                  <>
                    <Avatar profile={L.profile} size={34} />
                    <div className="cat-leader-name">{L.profile.meta.name}</div>
                    <div className="cat-leader-val mono">{L.profile._isRealUser || L.profile.id === "me" ? "Lv " : ""}{Math.round(L.value).toLocaleString()} {!L.profile._isRealUser && L.profile.id !== "me" ? P.CATS[c].unit : ""}</div>
                  </>
                ) : <div className="cat-leader-val mono dim">—</div>}
              </div>
            );
          })}
        </div>
      </Card>}

      {/* ranking — ranks tab only */}
      {lbTab === "ranks" && <div className="lb-list">
        {rows.map((r) => (
          <button className={"lb-row" + (r.isMe ? " me" : "")} key={r.id} onClick={() => setDetail(r.profile)}>
            <div className="lb-rank mono">{r.rank}</div>
            <Avatar profile={r.profile} size={46} />
            <div className="lb-id">
              <div className="lb-name">
                {r.profile.meta.name}
                {r.isMe && <span className="me-tag">YOU</span>}
                {r.profile._isRealUser && <span className="me-tag" style={{ background: "color-mix(in oklch,oklch(0.82 0.13 200) 14%,transparent)", color: "oklch(0.82 0.13 200)", borderColor: "color-mix(in oklch,oklch(0.82 0.13 200) 35%,transparent)" }}>REAL</span>}
              </div>
              <div className="lb-sub mono dim">Lv {r.level} · {r.streak}d streak</div>
            </div>
            <div className="lb-cats">
              {P.CAT_ORDER.map((c) => (
                <div className="lb-cat" key={c} title={`${P.CATS[c].name}`}>
                  <span className="lb-cat-key" style={{ color: `oklch(0.82 0.15 ${P.CATS[c].hue})` }}>{c}</span>
                  <span className="lb-cat-val mono">{windowLabel(r.profile, c)}</span>
                </div>
              ))}
            </div>
            <div className="lb-power">
              <div className="lb-power-n mono">{r.power}</div>
              <div className="lb-power-l">POWER</div>
            </div>
          </button>
        ))}
        {state.friends.length === 0 && !authUser && (
          <div className="empty" style={{ marginTop: 8 }}>No rivals yet. Sign in to compete with real friends.</div>
        )}
      </div>}

      {detail && <FriendDetail profile={detail} today={today} mode={mode} onClose={() => setDetail(null)} onMessage={onMessage} authUser={authUser} onRemoveFriend={onRefreshFriends ? (id) => { if (window.Bridge) Bridge.removeFriend(authUser.id, id).then(function(res) { if (!res || !res.error) onRefreshFriends(id); else console.error("[removeFriend]", res.error); }); } : null} />}

      {showAddFriend && authUser && (
        <AddFriendModal
          myId={authUser.id}
          onClose={() => setShowAddFriend(false)}
          onAdded={onRefreshFriends}
        />
      )}
    </div>
  );
}

function FriendDetail({ profile, today, mode, onClose, onMessage, authUser, onRemoveFriend }) {
  const P = window.PP;
  const isReal = profile._isRealUser;
  const [fullProfile, setFullProfile] = useState(null);
  const [friendState, setFriendState] = useState(null);
  const [loading, setLoading] = useState(isReal);

  useEffect(() => {
    if (!isReal || !window.Bridge) { setLoading(false); return; }
    setLoading(true);
    Promise.all([
      Bridge.getProfile(profile.id).catch(() => ({ data: null })),
      Bridge.getFriendGameState(profile.id).catch(() => ({ data: null })),
    ]).then(([{ data: p }, { data: gs }]) => {
      if (p) setFullProfile(p);
      if (gs) setFriendState(gs);
      setLoading(false);
    });
  }, [profile.id]);

  // Build full profile from their game_state.me
  const liveMe = friendState?.me;
  const computedProfile = liveMe ? {
    id: profile.id,
    _isRealUser: true,
    meta: { ...profile.meta, ...(liveMe.meta || {}), avatar: fullProfile?.avatar_url || liveMe.meta?.avatar || profile.meta.avatar || null },
    days: liveMe.days || {},
    business: liveMe.business || { income: [], youtube: [], channels: [], monthlyGoal: 0 },
    physiquePhotos: liveMe.physiquePhotos || [],
    unlocked: liveMe.unlocked || {},
    presets: liveMe.presets || {},
    goals: liveMe.goals || [],
  } : null;

  // Privacy settings — everything on by default
  const priv = friendState?.settings?.privacy || {};
  const show = {
    stats: priv.showStats !== false,
    calendar: priv.showCalendar !== false,
    tasks: priv.showTasks !== false,
    business: priv.showBusiness !== false,
    goals: priv.showGoals !== false,
    photos: priv.showPhotos !== false,
    achievements: priv.showAchievements !== false,
    friendsList: priv.showFriends !== false,
  };

  // Use computed (full day data) if available, fall back to snapshot.
  // Own profile (id==="me") has days+seed but no _scores — use decayedScores directly.
  const isOwnProfile = profile.id === "me";
  const liveSource = isOwnProfile ? profile : computedProfile;
  const active = computedProfile || profile;
  const scores = liveSource ? P.decayedScores(liveSource, today) : (profile._scores || {});
  const lvl = liveSource ? P.profileLevel(liveSource).level : (profile._level || 1);
  const power = liveSource ? P.power(liveSource, today) : (profile._power || 0);
  const streak = liveSource ? P.streak(liveSource, today) : (profile._streak || 0);

  const meta = {
    bio: fullProfile?.bio || liveMe?.meta?.bio || profile.meta.bio || "",
    height: fullProfile?.height || liveMe?.meta?.height || profile.meta.height || "",
    weight: fullProfile?.weight || liveMe?.meta?.weight || profile.meta.weight || "",
    age: fullProfile?.age || liveMe?.meta?.age || profile.meta.age || null,
    username: fullProfile?.username || "",
    avatar: fullProfile?.avatar_url || liveMe?.meta?.avatar || profile.meta.avatar || null,
  };

  const [clOpen, setClOpen] = useState({});
  const last7 = []; for (let i = 6; i >= 0; i--) last7.push(P.addDays(today, -i));
  const last30 = []; for (let i = 29; i >= 0; i--) last30.push(P.addDays(today, -i));
  const achv = active.days && Object.keys(active.days).length > 0 ? P.evalAchievements(active, today) : (!isReal ? P.evalAchievements(profile, today) : []);
  const got = achv.filter(a => a.got);
  const activeMode = mode || "week";

  function taskName(taskId) {
    const t = P.taskById(taskId);
    if (t) return t.name;
    const ct = (liveMe?.customTasks || []).find(c => c.id === taskId);
    return ct ? ct.name : taskId;
  }

  return (
    <Modal open wide onClose={onClose} title={profile.meta.name}>
      <div className="fd">

        {/* ── Header ── */}
        <div className="fd-top">
          <Avatar profile={{ meta: { name: profile.meta.name, avatar: meta.avatar } }} size={72} />
          <div className="fd-meta">
            <div className="fd-name">{profile.meta.name}</div>
            {meta.username && <div className="mono dim" style={{ fontSize: 12, marginBottom: 4 }}>@{meta.username}</div>}
            {meta.bio && <div className="fd-bio">{meta.bio}</div>}
            <div className="fd-vitals mono">
              {meta.height && <span>{meta.height}</span>}
              {meta.weight && <span>{meta.weight}</span>}
              {meta.age && <span>{meta.age} yrs</span>}
              <span className="dim">Lv {lvl} · ⚡{power}</span>
              {streak > 0 && <span style={{ color: "oklch(0.82 0.15 55)" }}>🔥{streak}d</span>}
            </div>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 6, marginLeft: "auto", flexShrink: 0 }}>
            {onMessage && profile.id !== "me" && (
              <button className="btn btn-sm btn-accent" onClick={() => { onMessage(profile.id); onClose(); }}>Message</button>
            )}
            {isReal && onRemoveFriend && authUser && profile.id !== authUser?.id && (
              <button className="btn btn-sm" style={{ color: "oklch(0.65 0.15 25)", borderColor: "color-mix(in oklch,oklch(0.65 0.15 25) 30%,transparent)" }} onClick={() => { onRemoveFriend(profile.id); onClose(); }}>Remove</button>
            )}
          </div>
        </div>

        {loading && <div className="dim mono" style={{ fontSize: 12, padding: "10px 0", textAlign: "center" }}>Loading full profile…</div>}

        {/* ── Attributes ── */}
        {show.stats && (
          <>
            <div className="dd-section-label">ATTRIBUTES</div>
            <div className="fd-attrs">
              {P.CAT_ORDER.map((c) => {
                const cl = P.catLevel(scores[c] || 0);
                return (
                  <div className="fd-attr" key={c} style={{ "--ah": `oklch(0.82 0.15 ${P.CATS[c].hue})` }}>
                    <div className="fd-attr-head"><span className="attr-key">{c}</span><span className="mono attr-lvl">Lv {cl.level}</span></div>
                    <Bar pct={cl.pct} hue={P.CATS[c].hue} height={6} />
                  </div>
                );
              })}
            </div>
          </>
        )}

        {/* ── 30-day calendar ── */}
        {show.calendar && (computedProfile || !isReal) && (
          <>
            <div className="dd-section-label">LAST 30 DAYS</div>
            <div className="fd-cal30">
              {last30.map((iso) => {
                const r = active.days[iso];
                const pct = r ? P.dayCompletion(r) : 0;
                const done = r && r.completed;
                return (
                  <div key={iso}
                    className={"fd-cal30-day" + (done ? " done" : pct > 0.05 ? " partial" : "")}
                    title={iso}
                  />
                );
              })}
            </div>
          </>
        )}

        {/* ── Last 7 days rings ── */}
        {show.calendar && (computedProfile || !isReal) && (
          <>
            <div className="dd-section-label">LAST 7 DAYS</div>
            <div className="fd-week">
              {last7.map((iso) => {
                const r = active.days[iso];
                const pct = r ? P.dayCompletion(r) : 0;
                return (
                  <div className="fd-day" key={iso}>
                    <div className="fd-day-name">{P.WEEKDAY_NAMES[P.weekday(iso)]}</div>
                    <Ring pct={pct} size={38} stroke={4}><span className="mono fd-day-pct">{r && r.completed ? "✓" : Math.round(pct * 100)}</span></Ring>
                  </div>
                );
              })}
            </div>
          </>
        )}

        {/* ── Last 2 days checklist (collapsed by default) ── */}
        {show.tasks && (computedProfile || !isReal) && [today, P.addDays(today, -1)].map(iso => {
          const r = active.days[iso];
          if (!r || !r.items || r.items.length === 0) return null;
          const cnt = P.dayDoneCount(r);
          const open = !!clOpen[iso];
          const label = iso === today ? "TODAY" : "YESTERDAY";
          return (
            <div key={iso}>
              <button className="fd-cl-toggle" onClick={() => setClOpen(s => ({ ...s, [iso]: !s[iso] }))}>
                <span className="dd-section-label" style={{ margin: 0 }}>{label} — {cnt.done}/{cnt.total} tasks {r.completed ? "✓" : ""}</span>
                <span className="fd-cl-arrow">{open ? "▲" : "▼"}</span>
              </button>
              {open && (() => {
                const sections = r.sectionOrder && r.sectionOrder.length ? r.sectionOrder : [...new Set(r.items.map(it => it.section))];
                return sections.map(sec => {
                  const items = r.items.filter(it => it.section === sec);
                  if (!items.length) return null;
                  return (
                    <div key={sec} className="fd-cl-sec">
                      <div className="fd-cl-sec-title">{sec}</div>
                      {items.map(it => {
                        const done = r.logs && r.logs[it.iid] && r.logs[it.iid].done;
                        return (
                          <div key={it.iid} className={"fd-cl-task" + (done ? " done" : "")}>
                            <span className="fd-cl-check">{done ? "✓" : "○"}</span>
                            <span className="fd-cl-name">{taskName(it.taskId)}</span>
                          </div>
                        );
                      })}
                    </div>
                  );
                });
              })()}
            </div>
          );
        })}

        {/* ── This period breakdown ── */}
        {show.stats && (computedProfile || !isReal) && (
          <>
            <div className="dd-section-label">THIS {activeMode.toUpperCase()}</div>
            <div className="fd-rundown">
              {P.CAT_ORDER.map((c) => {
                const wt = P.windowTotals(active, today, activeMode);
                return <div className="fd-run" key={c}><span className="mono" style={{ color: `oklch(0.82 0.15 ${P.CATS[c].hue})` }}>{Math.round(wt[c]).toLocaleString()}</span><span className="fd-run-l">{c} {P.CATS[c].unit}</span></div>;
              })}
            </div>
          </>
        )}

        {/* ── Earnings ── */}
        {show.business && (computedProfile || !isReal) && (() => {
          const money = P.moneyTotals(active, today);
          const dayAmt = (active.business?.income || []).filter(e => e.iso === today).reduce((a, e) => a + (e.amount || 0), 0);
          const yesterday = P.addDays(today, -1);
          const yestAmt = (active.business?.income || []).filter(e => e.iso === yesterday).reduce((a, e) => a + (e.amount || 0), 0);
          if (money.total === 0 && dayAmt === 0) return null;
          return (
            <>
              <div className="dd-section-label">EARNINGS</div>
              <div className="fd-money">
                <div className="fd-money-cell"><span className="mono fd-money-val">${dayAmt.toLocaleString()}</span><span className="fd-money-lbl">today</span></div>
                <div className="fd-money-cell"><span className="mono fd-money-val">${yestAmt.toLocaleString()}</span><span className="fd-money-lbl">yesterday</span></div>
                <div className="fd-money-cell"><span className="mono fd-money-val">${Math.round(money.week).toLocaleString()}</span><span className="fd-money-lbl">this week</span></div>
                <div className="fd-money-cell"><span className="mono fd-money-val">${Math.round(money.month).toLocaleString()}</span><span className="fd-money-lbl">this month</span></div>
              </div>
            </>
          );
        })()}

        {/* ── Goals ── */}
        {show.goals && (computedProfile || !isReal) && (active.goals || []).length > 0 && (
          <>
            <div className="dd-section-label">GOALS</div>
            <div className="fd-goals-list">
              {(active.goals || []).map(g => {
                const hue = g.hue != null ? g.hue : 162;
                const acc = `oklch(0.82 0.15 ${hue})`;
                let badge = null;
                if (g.type === "streak") {
                  const cur = window.goalStreak(g, today);
                  const best = window.goalBest(g);
                  badge = <span className="fd-goal-badge" style={{ color: acc }}>🔥 {cur}d streak · best {best}d</span>;
                } else if (g.type === "number") {
                  const recent = g.entries[today] ?? g.entries[P.addDays(today, -1)] ?? null;
                  badge = recent !== null ? <span className="fd-goal-badge" style={{ color: acc }}>{recent}{g.unit ? " " + g.unit : ""}{g.target ? " / " + g.target : ""}</span> : null;
                } else if (g.type === "counter") {
                  const total = Object.values(g.entries || {}).reduce((a, v) => a + (typeof v === "number" ? v : 0), 0);
                  badge = <span className="fd-goal-badge" style={{ color: acc }}>{total} total{g.target ? " · goal " + g.target + "/wk" : ""}</span>;
                }
                return (
                  <div key={g.id} className="fd-goal-row" style={{ "--gc": acc }}>
                    <span className="fd-goal-dot" />
                    <span className="fd-goal-name">{g.name}</span>
                    {badge}
                  </div>
                );
              })}
            </div>
          </>
        )}

        {/* ── Friends ── */}
        {show.friendsList && friendState && ((friendState.realFriends || []).length > 0 || (friendState.friends || []).filter(f => !f._isRealUser).length > 0) && (() => {
          const real = (friendState.realFriends || []);
          const demo = (friendState.friends || []).filter(f => !f._isRealUser);
          const all = [...real, ...demo].slice(0, 14);
          return (
            <>
              <div className="dd-section-label">FRIENDS ({all.length})</div>
              <div className="fd-friends-row">
                {all.map(f => (
                  <div key={f.id} className="fd-friend-chip" title={f.meta?.name || "?"}>
                    <Avatar profile={f} size={36} />
                    <span className="fd-friend-chip-name">{(f.meta?.name || "?").split(" ")[0]}</span>
                  </div>
                ))}
              </div>
            </>
          );
        })()}

        {/* ── Physique photos ── */}
        {show.photos && active.physiquePhotos && active.physiquePhotos.length > 0 && (
          <>
            <div className="dd-section-label">PHYSIQUE</div>
            <div className="fd-photos">{active.physiquePhotos.map(ph => <div className="fd-photo" key={ph.id}><img src={ph.data} alt="" />{ph.caption && <div className="photo-cap">{ph.caption}</div>}</div>)}</div>
          </>
        )}

        {/* ── Achievements ── */}
        {show.achievements && got.length > 0 && (
          <>
            <div className="dd-section-label">ACHIEVEMENTS · {got.length}/{achv.length}</div>
            <div className="fd-achv">
              {got.slice().reverse().slice(0, 18).map(a => <span className="fd-achv-pill" key={a.id} title={a.desc}>{a.icon} {a.name}</span>)}
            </div>
          </>
        )}

        {/* Privacy notice */}
        {isReal && !loading && friendState && Object.values(priv).some(v => v === false) && (
          <div className="dim" style={{ fontSize: 11, marginTop: 12 }}>Some sections hidden by their privacy settings.</div>
        )}

        {/* Waiting for first sync */}
        {isReal && !loading && !friendState && (
          <div className="dim" style={{ fontSize: 13, background: "var(--bg2)", border: "1px solid var(--line)", borderRadius: 10, padding: "12px 14px", marginTop: 8 }}>
            Full profile will appear after their next active session.
          </div>
        )}
      </div>
    </Modal>
  );
}

// ── Exercise database for PRs ─────────────────────────────────
const GYM_EXERCISES = [
  // Big lifts (weight)
  { id: "bench", name: "Bench Press", unit: "lbs", type: "weight" },
  { id: "squat", name: "Back Squat", unit: "lbs", type: "weight" },
  { id: "deadlift", name: "Deadlift", unit: "lbs", type: "weight" },
  { id: "ohp", name: "Overhead Press", unit: "lbs", type: "weight" },
  { id: "row", name: "Barbell Row", unit: "lbs", type: "weight" },
  { id: "incline", name: "Incline Bench", unit: "lbs", type: "weight" },
  { id: "rdl", name: "Romanian Deadlift", unit: "lbs", type: "weight" },
  { id: "front_squat", name: "Front Squat", unit: "lbs", type: "weight" },
  { id: "sumo", name: "Sumo Deadlift", unit: "lbs", type: "weight" },
  { id: "hip_thrust", name: "Hip Thrust", unit: "lbs", type: "weight" },
  { id: "pulldown", name: "Lat Pulldown", unit: "lbs", type: "weight" },
  { id: "curl", name: "Barbell Curl", unit: "lbs", type: "weight" },
  // Olympic
  { id: "clean_jerk", name: "Clean & Jerk", unit: "lbs", type: "weight" },
  { id: "snatch", name: "Snatch", unit: "lbs", type: "weight" },
  // Weighted bodyweight
  { id: "wp_pullup", name: "Weighted Pull-up", unit: "lbs", type: "weight" },
  { id: "wp_dip", name: "Weighted Dip", unit: "lbs", type: "weight" },
  // Bodyweight reps
  { id: "pullups_max", name: "Pull-ups (max reps)", unit: "reps", type: "reps" },
  { id: "pushups_max", name: "Push-ups (max reps)", unit: "reps", type: "reps" },
  { id: "dips_max", name: "Dips (max reps)", unit: "reps", type: "reps" },
  { id: "situps_max", name: "Sit-ups (max reps)", unit: "reps", type: "reps" },
  { id: "muscle_up", name: "Muscle-ups (max reps)", unit: "reps", type: "reps" },
  // Time
  { id: "plank_max", name: "Plank hold", unit: "sec", type: "time" },
  { id: "dead_hang", name: "Dead hang", unit: "sec", type: "time" },
  // Runs (lower = better, but show raw)
  { id: "mile_run", name: "1 Mile Run", unit: "min", type: "time_low" },
  { id: "5k_run", name: "5K Run", unit: "min", type: "time_low" },
  { id: "10k_run", name: "10K Run", unit: "min", type: "time_low" },
  // Jumps
  { id: "box_jump", name: "Box Jump", unit: "in", type: "dist" },
  { id: "vert", name: "Vertical Jump", unit: "in", type: "dist" },
  // Custom exercises (logged via "Other" input)
];

const PR_GROUPS = ["Big Lifts", "Olympic", "Bodyweight", "Timed", "Cardio", "Other"];

function GymPRs({ authUser, state }) {
  const [prs, setPrs] = useState([]); // {exercise, pr_value, unit, reps, user_id, logged_at, id, _name}
  const [loading, setLoading] = useState(false);
  const [showForm, setShowForm] = useState(false);
  const [formExercise, setFormExercise] = useState(GYM_EXERCISES[0].id);
  const [formCustom, setFormCustom] = useState("");
  const [formVal, setFormVal] = useState("");
  const [formUnit, setFormUnit] = useState("lbs");
  const [formReps, setFormReps] = useState(1);
  const [formNotes, setFormNotes] = useState("");
  const [filter, setFilter] = useState("all"); // "all" | "mine" | exercise id

  const friendNames = {};
  if (authUser) friendNames[authUser.id] = "You";
  (state.friends || []).forEach(f => { if (f._isRealUser && f.id) friendNames[f.id] = f.meta.name; });

  function load() {
    if (!authUser || !window.Bridge) return;
    setLoading(true);
    Bridge.getFriendsPRs(authUser.id).then(({ data }) => {
      setPrs((data || []).map(r => ({ ...r, _name: friendNames[r.user_id] || "Friend" })));
      setLoading(false);
    }).catch(() => setLoading(false));
  }

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

  // Best PR per exercise per user
  const bestByExAndUser = {};
  prs.forEach(r => {
    const key = r.exercise + "|" + r.user_id;
    if (!bestByExAndUser[key] || r.pr_value > bestByExAndUser[key].pr_value) bestByExAndUser[key] = r;
  });

  // Exercises that at least one person has logged
  const loggedExercises = [...new Set(prs.map(r => r.exercise))];
  const knownIds = GYM_EXERCISES.map(e => e.id);
  const exercisesForDisplay = [...GYM_EXERCISES.filter(e => loggedExercises.includes(e.id)), ...loggedExercises.filter(id => !knownIds.includes(id)).map(id => ({ id, name: id, unit: prs.find(r => r.exercise === id)?.unit || "lbs", type: "weight" }))];

  function submitPR() {
    if (!authUser || !window.Bridge) return;
    const exId = formExercise === "__custom__" ? formCustom.trim() : formExercise;
    if (!exId || !formVal) return;
    const ex = GYM_EXERCISES.find(e => e.id === exId);
    Bridge.logPR(authUser.id, exId, formVal, ex?.unit || formUnit, formReps, formNotes).then(() => {
      setShowForm(false); setFormVal(""); setFormNotes(""); load();
    });
  }

  function deletePR(prId) {
    if (!window.Bridge) return;
    Bridge.deletePR(prId).then(() => load());
  }

  const users = [...new Set(prs.map(r => r.user_id))];

  if (!authUser) {
    return (
      <div className="empty" style={{ marginTop: 16 }}>
        Sign in to log and compete on gym PRs with friends.
      </div>
    );
  }

  return (
    <div className="gym-prs">
      <div className="gpr-header">
        <div>
          <div className="dd-section-label" style={{ marginBottom: 4 }}>GYM PRs — compete with your squad</div>
          <div className="dim mono" style={{ fontSize: 11 }}>Log your personal records and see where you rank among friends.</div>
        </div>
        <button className="btn btn-sm btn-accent" onClick={() => setShowForm(!showForm)}>+ Log PR</button>
      </div>

      {showForm && (
        <div className="gpr-form">
          <div className="row2">
            <Field label="Exercise">
              <select className="inp" value={formExercise} onChange={e => { setFormExercise(e.target.value); const ex = GYM_EXERCISES.find(x => x.id === e.target.value); if (ex) setFormUnit(ex.unit); }}>
                {GYM_EXERCISES.map(e => <option key={e.id} value={e.id}>{e.name}</option>)}
                <option value="__custom__">Other (type below)</option>
              </select>
            </Field>
            {formExercise === "__custom__" && (
              <Field label="Custom exercise name">
                <input className="inp" value={formCustom} onChange={e => setFormCustom(e.target.value)} placeholder="e.g. Log Press" />
              </Field>
            )}
          </div>
          <div className="row2">
            <Field label={"PR value (" + formUnit + ")"}><input className="inp" type="number" value={formVal} onChange={e => setFormVal(e.target.value)} placeholder="e.g. 225" /></Field>
            <Field label="Unit"><select className="inp" value={formUnit} onChange={e => setFormUnit(e.target.value)}><option>lbs</option><option>kg</option><option>reps</option><option>sec</option><option>min</option><option>in</option><option>cm</option></select></Field>
          </div>
          <Field label="Notes (optional)"><input className="inp" value={formNotes} onChange={e => setFormNotes(e.target.value)} placeholder="e.g. paused, raw, no belt..." /></Field>
          <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
            <button className="btn btn-sm" onClick={() => setShowForm(false)}>Cancel</button>
            <button className="btn btn-sm btn-accent" onClick={submitPR} disabled={!formVal || (formExercise === "__custom__" && !formCustom.trim())}>Save PR</button>
          </div>
        </div>
      )}

      {loading && <div className="dim mono" style={{ fontSize: 12, padding: 12 }}>Loading PRs…</div>}

      {!loading && exercisesForDisplay.length === 0 && (
        <div className="empty" style={{ marginTop: 16 }}>No PRs logged yet. Be the first to set a record!</div>
      )}

      {!loading && exercisesForDisplay.length > 0 && (
        <div className="gpr-table" style={{"--gpr-cols": users.length}}>
          <div className="gpr-thead">
            <span>Exercise</span>
            {users.map(uid => <span key={uid} className="gpr-th-user">{friendNames[uid] || "?"}</span>)}
          </div>
          {exercisesForDisplay.map(ex => {
            const entries = users.map(uid => bestByExAndUser[ex.id + "|" + uid]);
            if (entries.every(e => !e)) return null;
            const vals = entries.map(e => e?.pr_value || 0);
            const maxVal = Math.max(...vals);
            return (
              <div className="gpr-row" key={ex.id}>
                <span className="gpr-ex-name">{ex.name}</span>
                {users.map((uid, i) => {
                  const e = entries[i];
                  const isTop = e && e.pr_value === maxVal && maxVal > 0;
                  return (
                    <span key={uid} className={"gpr-cell" + (isTop ? " gpr-top" : "") + (!e ? " gpr-empty" : "")}>
                      {e ? (
                        <span title={e.notes || ""}>
                          {e.pr_value} {e.unit}
                          {uid === authUser.id && <button className="gpr-del" onClick={() => deletePR(e.id)} title="delete PR">✕</button>}
                        </span>
                      ) : "—"}
                    </span>
                  );
                })}
              </div>
            );
          }).filter(Boolean)}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { Leaderboard, Avatar, FriendDetail, profileStats });
