// ============================================================
// sections-b.jsx — Live Feed, Leaderboards, Badges
// ============================================================

// ---- LIVE ACTIVITY FEED ----
function kindMeta(kind) {
  return {
    run:    { tag: "RUN",   c: "var(--teal)" },
    badge:  { tag: "BADGE", c: "oklch(0.78 0.13 92)" },
    streak: { tag: "STRK",  c: "oklch(0.72 0.13 150)" },
    team:   { tag: "TEAM",  c: "oklch(0.72 0.12 280)" },
  }[kind] || { tag: "LOG", c: "var(--teal)" };
}

function agoLabel(t) {
  if (t <= 0) return "today";
  if (t < 60) return t + " min ago";
  if (t < 1440) return Math.floor(t / 60) + " hr ago";
  const d = Math.floor(t / 1440);
  return d === 1 ? "yesterday" : d + " days ago";
}

function Feed() {
  const [items, setItems] = useState(() => FEED_DATA.map(it => ({ ...it })));
  const [count, setCount] = useState(15 * 60);

  // Countdown to the next sync.
  useEffect(() => {
    const tick = setInterval(() => setCount(c => (c <= 1 ? 15 * 60 : c - 1)), 1000);
    return () => clearInterval(tick);
  }, []);

  // When the countdown wraps, pull fresh real data from the server.
  useEffect(() => {
    if (count !== 15 * 60) return;
    let cancelled = false;
    fetchClubData().then(d => {
      if (cancelled || !d || !d.feed) return;
      const prevIds = new Set(items.map(i => i.id));
      setItems(d.feed.map((it, i) => ({ ...it, fresh: i === 0 && !prevIds.has(it.id) })));
    }).catch(() => {});
    return () => { cancelled = true; };
  }, [count]);

  const mm = String(Math.floor(count / 60)).padStart(2, "0");
  const ss = String(count % 60).padStart(2, "0");

  return (
    <section id="feed" className="section-pad feed-sec">
      <div className="wrap feed-wrap">
        <div className="feed-head">
          <div>
            <Reveal><span className="eyebrow">// 03 — Live activity</span></Reveal>
            <Reveal delay={60}><h2 className="sec-title">Every run shows up here.</h2></Reveal>
            <Reveal delay={120}><p className="sec-lead">Pulled straight from Strava and refreshed automatically. Lace up and you're on the board within the quarter-hour.</p></Reveal>
          </div>
          <Reveal delay={120} className="feed-timer card card-corner">
            <div className="ft-label mono">NEXT SYNC</div>
            <div className="ft-clock mono tnum">{mm}:{ss}</div>
            <div className="ft-sub mono">refresh interval · 15:00</div>
          </Reveal>
        </div>
        {items.length === 0 ? (
          <p className="empty-note">// no activities synced yet — connect Strava and your runs land here</p>
        ) : (
          <Reveal delay={80} className="feed-list card">
            {items.map((it) => {
              const km = kindMeta(it.kind);
              return (
                <div key={it.id} className={"feed-row" + (it.fresh ? " feed-row--fresh" : "")}>
                  <span className="feed-tag mono" style={{ color: km.c, borderColor: km.c }}>{km.tag}</span>
                  <div className="feed-main">
                    <span className="feed-text"><b>{it.who}</b> {it.action}</span>
                    <span className="feed-meta mono">{it.meta}</span>
                  </div>
                  <span className="feed-time mono">{agoLabel(it.t)}</span>
                </div>
              );
            })}
          </Reveal>
        )}
      </div>
      <style>{`
        .feed-head { display: grid; grid-template-columns: 1fr auto; gap: 32px; align-items: end; }
        .feed-timer { padding: 18px 22px; min-width: 200px; text-align: left; }
        .ft-label { font-size: 11px; letter-spacing: .16em; color: var(--text-dim); display: flex; align-items: center; gap: 8px; }
        .ft-clock { font-family: var(--font-display); font-size: 44px; color: var(--teal); line-height: 1; margin-top: 8px; letter-spacing: .02em; }
        .ft-sub { font-size: 10px; letter-spacing: .12em; color: var(--text-faint); margin-top: 6px; }
        .feed-list { margin-top: 40px; overflow: hidden; }
        .feed-row { display: grid; grid-template-columns: auto 1fr auto; gap: 18px; align-items: center; padding: 17px 24px; border-bottom: 1px solid var(--line-2); }
        .feed-row:last-child { border-bottom: 0; }
        .feed-row--fresh { animation: feedIn .55s cubic-bezier(.22,.61,.36,1); background: var(--teal-soft); }
        @keyframes feedIn { from { opacity: 0; transform: translateY(-12px); background: var(--teal-soft); } to { background: transparent; } }
        .feed-tag { font-size: 10px; font-weight: 700; letter-spacing: .1em; border: 1px solid; border-radius: 3px; padding: 4px 7px; width: 56px; text-align: center; }
        .feed-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
        .feed-text { font-size: 15px; }
        .feed-text b { font-weight: 600; }
        .feed-meta { font-size: 11px; color: var(--text-faint); letter-spacing: .04em; }
        .feed-time { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
        @media (max-width: 760px){ .feed-head { grid-template-columns: 1fr; } .feed-meta { display:none; } }
      `}</style>
    </section>
  );
}

// ---- LEADERBOARDS ----
function Leaderboard({ onSelect }) {
  const keys = Object.keys(LEADERBOARDS);
  const [tab, setTab] = useState("distance");
  const cfg = LEADERBOARDS[tab];
  const ranked = rankBy(tab);
  const max = ranked.length ? cfg.get(ranked[0]) || 1 : 1;
  const podium = ranked.length >= 3;

  return (
    <section id="leaderboard" className="section-pad lb-sec grid-bg">
      <div className="wrap">
          <Reveal><span className="eyebrow">// 01 — Monthly leaderboards</span></Reveal>
        <Reveal delay={40} className="lb-month">
          <a className="mn-btn mono" href={"/?month=" + MONTHNAV.prev} aria-label="Previous month">‹ Prev</a>
          <span className="mn-label">{MONTHNAV.label}</span>
          {MONTHNAV.next
            ? <a className="mn-btn mono" href={"/?month=" + MONTHNAV.next} aria-label="Next month">Next ›</a>
            : <span className="mn-btn mn-btn--off mono" aria-disabled="true">Next ›</span>}
        </Reveal>
        <div className="lb-top">
          <Reveal delay={60}><h2 className="sec-title">Climb the board.</h2></Reveal>
          <Reveal delay={100} className="lb-tabs">
            {keys.map(k => (
              <button key={k} className={"lb-tab mono" + (k === tab ? " on" : "")} onClick={() => setTab(k)}>
                {LEADERBOARDS[k].label}
              </button>
            ))}
          </Reveal>
        </div>

        {ranked.length === 0 ? (
          <p className="empty-note">// no runners on the board yet — be the first to connect Strava</p>
        ) : (
          <Reveal delay={80} className={"lb-board lb-board--" + (podium ? "podium" : "list")}>
            {podium && (
              <div className="lb-podium">
                {[1, 0, 2].map((idx) => {
                  const m = ranked[idx]; const place = idx + 1;
                  return (
                    <button key={m.id} className={"pod pod-" + place} onClick={() => onSelect(m)}>
                      <div className="pod-rank mono">#{place}</div>
                      <Avatar m={m} size={place === 1 ? 64 : 52} />
                      <div className="pod-name">{m.name}</div>
                      <div className="pod-val mono"><b>{cfg.fmt(cfg.get(m))}</b> {cfg.unit}</div>
                      <div className="pod-bar"><span style={{ height: place === 1 ? "100%" : place === 2 ? "72%" : "54%" }}></span></div>
                    </button>
                  );
                })}
              </div>
            )}
            <div className="lb-list card">
              {(podium ? ranked.slice(3) : ranked).map((m, i) => {
                const rank = podium ? i + 4 : i + 1;
                const pct = (cfg.get(m) / max) * 100;
                const top = rank <= 3;
                return (
                  <button key={m.id} className={"lb-row" + (top ? " lb-row--top" : "")} onClick={() => onSelect(m)}>
                    <span className={"lb-rank mono" + (top ? " hot" : "")}>{String(rank).padStart(2, "0")}</span>
                    <Avatar m={m} size={38} />
                    <div className="lb-id">
                      <span className="lb-name">{m.name}</span>
                      <span className="lb-role mono">@{m.handle}</span>
                    </div>
                    <div className="lb-bar"><span style={{ width: pct + "%" }}></span></div>
                    <div className="lb-val mono"><b>{cfg.fmt(cfg.get(m))}</b><span className="lb-unit">{cfg.unit}</span></div>
                  </button>
                );
              })}
            </div>
          </Reveal>
        )}
        {ranked.length > 0 && <Reveal delay={60}><p className="lb-hint mono">↳ select any runner to open their profile</p></Reveal>}
      </div>
      <style>{`
        .lb-month { display: inline-flex; align-items: center; gap: 14px; margin-top: 18px; }
        .mn-label { font-family: var(--font-display); font-weight: 500; font-size: clamp(18px, 2.2vw, 24px); color: var(--text); min-width: 8ch; text-align: center; }
        .mn-btn { font-size: 12px; letter-spacing: .06em; padding: 8px 14px; border-radius: 4px; border: 1px solid var(--line); color: var(--text-dim); text-decoration: none; transition: all .15s; white-space: nowrap; }
        .mn-btn:hover { color: var(--teal); border-color: var(--teal); }
        .mn-btn--off { opacity: .35; pointer-events: none; }
        .lb-sec { padding-bottom: clamp(40px, 6vw, 72px); }
        .lb-top { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; flex-wrap: wrap; margin-bottom: 36px; margin-top: 26px; }
        .lb-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
        .lb-tab { font-size: 12px; letter-spacing: .04em; padding: 9px 14px; border-radius: 4px; border: 1px solid var(--line); background: transparent; color: var(--text-dim); cursor: pointer; transition: all .15s; }
        .lb-tab:hover { color: var(--text); border-color: var(--text-faint); }
        .lb-tab.on { background: var(--teal); border-color: var(--teal); color: #00171a; font-weight: 600; }
        .lb-podium { display: grid; grid-template-columns: repeat(3,1fr); gap: 16px; align-items: end; margin-bottom: 16px; }
        .pod { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 22px 16px 0; display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: pointer; transition: border-color .2s, transform .2s; overflow: hidden; }
        .pod:hover { border-color: var(--teal); transform: translateY(-3px); }
        .pod-1 { border-color: color-mix(in oklab, var(--teal) 50%, var(--line)); }
        .pod-rank { font-family: var(--font-display); font-size: 26px; color: var(--teal); }
        .pod-1 .pod-rank { font-size: 34px; }
        .pod-name { font-weight: 600; font-size: 15px; text-align: center; color: var(--teal); }
        .pod-val { font-size: 12px; color: var(--text-dim); } .pod-val b { color: var(--text); font-size: 15px; }
        .pod-bar { width: 60%; margin-top: 6px; height: 70px; display: flex; align-items: flex-end; }
        .pod-bar span { width: 100%; background: linear-gradient(var(--teal), transparent); border-radius: 3px 3px 0 0; display: block; }
        .lb-list { overflow: hidden; }
        .lb-row { width: 100%; display: grid; grid-template-columns: 30px auto 1fr minmax(120px,1.4fr) auto; gap: 16px; align-items: center; padding: 14px 22px; border: 0; border-bottom: 1px solid var(--line-2); background: transparent; color: var(--text); cursor: pointer; text-align: left; transition: background .15s; }
        .lb-row:last-child { border-bottom: 0; }
        .lb-row:hover { background: var(--teal-soft); }
        .lb-rank { font-size: 14px; color: var(--text-faint); font-weight: 600; }
        .lb-rank.hot { color: var(--teal); }
        .lb-id { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
        .lb-name { font-weight: 600; font-size: 15px; }
        .lb-role { font-size: 11px; color: var(--text-faint); letter-spacing: .02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
        .lb-bar { height: 7px; background: var(--line-2); border-radius: 4px; overflow: hidden; }
        .lb-bar span { display: block; height: 100%; background: linear-gradient(90deg, color-mix(in oklab, var(--teal) 60%, var(--navy)), var(--teal)); border-radius: 4px; transition: width .8s cubic-bezier(.22,.61,.36,1); }
        .lb-val { text-align: right; white-space: nowrap; font-size: 12px; color: var(--text-faint); }
        .lb-val b { font-family: var(--font-display); font-weight: 500; font-size: 21px; color: var(--text); margin-right: 6px; }
        .lb-hint { font-size: 11px; color: var(--text-faint); margin-top: 16px; letter-spacing: .04em; }
        @media (max-width: 760px){ .lb-row { grid-template-columns: 26px auto 1fr auto; } .lb-bar { display: none; } .lb-role { display:none; } .lb-podium { grid-template-columns: 1fr; } }
      `}</style>
    </section>
  );
}

// ---- BADGES ----
function Badges({ onSelect }) {
  return (
    <section id="badges" className="section-pad">
      <div className="wrap">
        <Reveal><span className="eyebrow">// 03 — Achievements</span></Reveal>
        <Reveal delay={60}><h2 className="sec-title">Cyber-themed badges,<br />earned in the field.</h2></Reveal>
        <Reveal delay={100}><p className="sec-lead">Unlocked through real activity. Every emblem maps a security discipline onto a running habit.</p></Reveal>
        <div className="badge-grid">
          {BADGES.map((b, i) => {
            const holders = MEMBERS.filter(m => m.badges.includes(b.id));
            return (
              <Reveal key={b.id} delay={80 + i * 50} className="badge-card card card-corner">
                <div className="badge-emblem">
                  <span className="badge-hex" aria-hidden="true"></span>
                  <span className="badge-code mono">{b.code}</span>
                </div>
                <div className="badge-body">
                  <div className="badge-name">{b.name}</div>
                  <div className="badge-desc">{b.desc}</div>
                </div>
                <div className="badge-foot mono">
                  <span className="badge-holders">{b.holders} earned</span>
                  <span className="badge-avs">{holders.slice(0, 4).map(m => (
                    <span key={m.id} className="ba" onClick={(e) => { e.stopPropagation(); onSelect(m); }} title={m.name}>{m.name[0]}</span>
                  ))}</span>
                </div>
              </Reveal>
            );
          })}
        </div>
      </div>
      <style>{`
        .badge-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 16px; margin-top: 48px; }
        .badge-card { padding: 24px; display: flex; flex-direction: column; gap: 18px; transition: border-color .2s, transform .2s; }
        .badge-card:hover { border-color: color-mix(in oklab, var(--teal) 55%, var(--line)); transform: translateY(-3px); }
        .badge-card:hover .badge-hex { box-shadow: 0 0 30px -6px var(--teal); }
        .badge-emblem { position: relative; width: 64px; height: 72px; display: grid; place-items: center; }
        .badge-hex { position: absolute; inset: 0; background: linear-gradient(145deg, var(--raised), var(--panel-2)); border: 1px solid var(--line);
          clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); transition: box-shadow .25s; }
        .badge-hex::after { content:""; position:absolute; inset:4px; border:1px solid var(--teal-soft); clip-path: inherit; }
        .badge-code { position: relative; font-size: 14px; font-weight: 700; color: var(--teal); letter-spacing: .02em; }
        .badge-name { font-family: var(--font-display); font-weight: 500; font-size: 21px; }
        .badge-desc { color: var(--text-dim); font-size: 13.5px; line-height: 1.5; margin-top: 6px; }
        .badge-foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line-2); display: flex; align-items: center; justify-content: space-between; }
        .badge-holders { font-size: 11px; letter-spacing: .08em; color: var(--text-faint); }
        .badge-avs { display: flex; }
        .ba { width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font-size: 11px; font-weight: 700; color: var(--text);
          background: var(--raised); border: 1px solid var(--bg); margin-left: -7px; cursor: pointer; transition: transform .15s; }
        .ba:hover { transform: translateY(-2px); color: var(--teal); }
        @media (max-width: 900px){ .badge-grid { grid-template-columns: repeat(2,1fr); } }
        @media (max-width: 560px){ .badge-grid { grid-template-columns: 1fr; } }
      `}</style>
    </section>
  );
}

// ---- WEDNESDAY ATTENDANCE ----
function Attendance() {
  const labels = ATTENDANCE.labels || [];
  const rows = [...(ATTENDANCE.rows || [])].sort(
    (a, b) => b.attended - a.attended || a.name.localeCompare(b.name)
  );
  return (
    <section id="attendance" className="section-pad att-sec grid-bg">
      <div className="wrap">
        <Reveal><span className="eyebrow">// 02 — Wednesday attendance</span></Reveal>
        <Reveal delay={60}><h2 className="sec-title">Who showed up on Wednesdays.</h2></Reveal>
        <Reveal delay={100}><p className="sec-lead">Every Wednesday is a club run — log one that day and you're marked present.</p></Reveal>

        {rows.length === 0 ? (
          <p className="empty-note">// no runners on the board yet</p>
        ) : (
          <Reveal delay={80} className="att-card card">
            <div className="att-scroll">
              <div className="att-row att-row--head">
                <div className="att-name-h mono">Runner</div>
                <div className="att-cells">
                  {labels.map((d, i) => (
                    <div key={i} className="att-col-h">
                      <span className="att-wk mono">W{i + 1}</span>
                      <span className="att-day mono">{d}</span>
                    </div>
                  ))}
                </div>
                <div className="att-total-h mono">Total</div>
              </div>
              {rows.map((r) => {
                const full = r.total > 0 && r.attended === r.total;
                return (
                  <div key={r.name} className="att-row">
                    <div className="att-name">{r.name}</div>
                    <div className="att-cells">
                      {r.wednesdays.map((p, i) => (
                        <div key={i} className="att-col">
                          <span className={"att-dot" + (p ? " on" : "")}>{p ? "✓" : ""}</span>
                        </div>
                      ))}
                    </div>
                    <div className={"att-score mono" + (full ? " full" : "")}>{r.attended}/{r.total}</div>
                  </div>
                );
              })}
            </div>
          </Reveal>
        )}
      </div>
      <style>{`
        .att-sec { padding-top: clamp(12px, 2.5vw, 32px); }
        .att-card { margin-top: 44px; padding: 4px 0; overflow: hidden; }
        .att-scroll { overflow-x: auto; }
        .att-row { display: flex; align-items: center; gap: 18px; padding: 14px 24px; border-bottom: 1px solid var(--line-2); min-width: 420px; }
        .att-row:last-child { border-bottom: 0; }
        .att-row--head { border-bottom: 1px solid var(--line); }
        .att-row:not(.att-row--head):hover { background: var(--teal-soft); }
        .att-name, .att-name-h { flex: 1 1 auto; min-width: 96px; }
        .att-name { font-weight: 600; font-size: 15px; }
        .att-name-h { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-faint); }
        .att-cells { display: flex; gap: 8px; flex: none; }
        .att-col, .att-col-h { width: 34px; display: flex; flex-direction: column; align-items: center; gap: 3px; }
        .att-wk { font-size: 11px; color: var(--teal); letter-spacing: .04em; }
        .att-day { font-size: 10px; color: var(--text-faint); }
        .att-dot { width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center; font-size: 13px; font-weight: 700;
          border: 1px solid var(--line); color: transparent; background: transparent; transition: all .15s; }
        .att-dot.on { background: var(--teal); border-color: var(--teal); color: #00171a; box-shadow: 0 0 16px -6px var(--teal); }
        .att-total-h { width: 56px; text-align: right; flex: none; font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-faint); }
        .att-score { width: 56px; text-align: right; flex: none; font-size: 14px; color: var(--text-dim); font-weight: 600; }
        .att-score.full { color: var(--teal); }
      `}</style>
    </section>
  );
}

Object.assign(window, { Feed, Leaderboard, Badges, Attendance });
