// 30-day submission strip — a tight, single-row visualization of when
// mirrorsedger has been grinding. Replaces the old GitHub-style year grid
// (which looked sparse for a runner who can't play every day) with a
// glanceable "what have I been up to lately" indicator.
//
// Visual: 30 cells, oldest left, today right. Each cell is a day; intensity
// scales with submissions that day. Pairs with three stat callouts:
//   - sessions in window
//   - current streak (consecutive days ending today)
//   - longest streak in window
//
// Reads from window.RUN_DATA.recentActivity (filtered to mirrorsedger's
// submissions) plus the curated `history` arrays.

function RunHeatmap({ days = 30 }) {
  useDataTick();
  const recent = window.RUN_DATA.recentActivity;
  const [ref, visible] = useReveal();

  // Aggregate mirrorsedger's submissions into YYYY-MM-DD → count.
  const submissions = new Map();
  function bump(dateStr) {
    if (!dateStr) return;
    const k = dateStr.slice(0, 10);
    submissions.set(k, (submissions.get(k) || 0) + 1);
  }
  if (Array.isArray(recent)) {
    for (const r of recent) if (r.isMe) bump(r.ts);
  }
  for (const run of window.RUN_DATA.runs) {
    if (Array.isArray(run.history)) for (const h of run.history) bump(h.date);
  }

  // Build a `days`-day window ending today, in UTC to avoid DST drift.
  const today = new Date();
  const todayUTC = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()));
  const cells = [];
  let totalCount = 0;
  let activeDays = 0;
  let maxCount = 0;
  for (let i = days - 1; i >= 0; i--) {
    const d = new Date(todayUTC);
    d.setUTCDate(todayUTC.getUTCDate() - i);
    const k = d.toISOString().slice(0, 10);
    const c = submissions.get(k) || 0;
    if (c > 0) { activeDays++; totalCount += c; if (c > maxCount) maxCount = c; }
    cells.push({ date: d, key: k, count: c });
  }

  // Streaks within the window. "current" = consecutive active days ending
  // today; "longest" = longest run of consecutive active days anywhere in
  // the window. Both useful — current rewards a hot streak, longest shows
  // the best stretch you've put together this month.
  let currentStreak = 0;
  for (let i = cells.length - 1; i >= 0; i--) {
    if (cells[i].count > 0) currentStreak++;
    else break;
  }
  let longestStreak = 0;
  let run = 0;
  for (const c of cells) {
    if (c.count > 0) { run++; if (run > longestStreak) longestStreak = run; }
    else run = 0;
  }

  // Bucket count → colour level (0..4). With small windows and bursty play,
  // a relative scale (vs maxCount) feels honest — the busiest day is "max"
  // even if that's just 3 submissions.
  function level(c) {
    if (c === 0) return 0;
    if (maxCount <= 1) return 4;
    const pct = c / maxCount;
    if (pct >= 0.75) return 4;
    if (pct >= 0.5) return 3;
    if (pct >= 0.25) return 2;
    return 1;
  }

  // Month boundaries — render a tiny tick + month label whenever the month
  // changes within the window. Most of the time this fires once (e.g. APR
  // crossing into MAY); occasionally twice if the window spans 3 months,
  // which doesn't happen for `days <= 31` but defensive anyway.
  const monthTicks = [];
  let lastMonth = -1;
  cells.forEach((c, i) => {
    const m = c.date.getUTCMonth();
    if (m !== lastMonth) {
      monthTicks.push({
        index: i,
        label: c.date.toLocaleDateString("en-GB", { month: "short", timeZone: "UTC" }).toUpperCase(),
      });
      lastMonth = m;
    }
  });

  return (
    <section className="pulse-section" id="training">
      <SectionHead
        n="02"
        kicker="TRAINING"
        title="Last 30 days on the boards."
        sub="A glanceable view of when I've been grinding — submissions, current streak, and best stretch within the window."
      />
      <div className={`pulse ${visible ? "rv" : ""}`} ref={ref}>
        <div className="pulse__head">
          <div className="pulse__title">
            <span className="pulse__kicker">TRAINING PULSE · LAST {days} DAYS</span>
            <span className="pulse__sub">mirrorsedger · personal submissions</span>
          </div>
          <div className="pulse__stats">
            <div className="pulse__stat">
              <span className="pulse__stat-num">{totalCount}</span>
              <span className="pulse__stat-lbl">SESSIONS</span>
            </div>
            <div className="pulse__stat">
              <span className="pulse__stat-num">{currentStreak}<span className="pulse__stat-unit">d</span></span>
              <span className="pulse__stat-lbl">STREAK</span>
            </div>
            <div className="pulse__stat">
              <span className="pulse__stat-num">{longestStreak}<span className="pulse__stat-unit">d</span></span>
              <span className="pulse__stat-lbl">BEST</span>
            </div>
          </div>
        </div>
        <div className="pulse__strip" role="img"
             aria-label={`${totalCount} submissions on ${activeDays} of last ${days} days`}>
          {cells.map((c, i) => {
            const lv = level(c.count);
            const isToday = i === cells.length - 1;
            const dayNum = c.date.getUTCDate();
            const showTick = monthTicks.some(t => t.index === i);
            const tooltip = `${c.date.toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" })}: ${c.count} submission${c.count === 1 ? "" : "s"}`;
            return (
              <div key={c.key} className={`pulse__day pulse__day--${lv} ${isToday ? "is-today" : ""}`}>
                <div className="pulse__cell" title={tooltip}></div>
                {(i % 7 === 0 || isToday) && (
                  <span className="pulse__daynum">{dayNum}</span>
                )}
                {showTick && (
                  <span className="pulse__monthtick">{monthTicks.find(t => t.index === i).label}</span>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { RunHeatmap });
