// MY JOURNEY — personal analytics view
// Pure React component that takes (athleteId, allSets) and renders trends, heatmaps, charts, insights.

const JourneyView = ({ athleteId, allSets, athletes, today }) => {
  const D = window.FITNESS_DATA;
  const me = athletes[athleteId];
  const [range, setRange] = React.useState("30D");

  // Compute date range
  const todayDate = new Date(today + "T00:00:00");
  const ranges = {
    "7D": { days: 7, label: "Last 7 days" },
    "30D": { days: 30, label: "Last 30 days" },
    "3M": { days: 90, label: "Last 3 months" },
    "6M": { days: 180, label: "Last 6 months" },
    "ALL": { days: 999, label: "All time" }
  };
  const rangeInfo = ranges[range];
  const cutoffDate = new Date(todayDate);
  cutoffDate.setDate(cutoffDate.getDate() - (rangeInfo.days - 1));
  const cutoffStr = cutoffDate.toISOString().slice(0, 10);

  // My sets in range
  const mySets = React.useMemo(() => allSets.filter(s => s.athlete === athleteId), [allSets, athleteId]);
  const rangeSets = React.useMemo(() => mySets.filter(s => s.date >= cutoffStr), [mySets, cutoffStr]);

  // === Compute aggregate stats ===
  const totalVolume = rangeSets.reduce((sum, s) => {
    const w = s.weight || me.bodyweight || 70;
    return sum + w * s.reps;
  }, 0);
  const totalSets = rangeSets.length;
  const totalReps = rangeSets.reduce((sum, s) => sum + s.reps, 0);
  const uniqueDates = new Set(rangeSets.map(s => s.date));
  const workoutDays = uniqueDates.size;
  const prsInRange = rangeSets.filter(s => s.isPR).length;

  // Workout days vs total days (consistency %)
  const consistencyPct = Math.round((workoutDays / Math.min(rangeInfo.days, 180)) * 100);

  // === Volume trend chart (per-day volume) ===
  const dailyVolume = React.useMemo(() => {
    const map = {};
    rangeSets.forEach(s => {
      const w = s.weight || me.bodyweight || 70;
      map[s.date] = (map[s.date] || 0) + w * s.reps;
    });
    return map;
  }, [rangeSets, me]);

  // Build sequential days array
  const days = [];
  for (let i = 0; i < Math.min(rangeInfo.days, 180); i++) {
    const d = new Date(todayDate);
    d.setDate(d.getDate() - (rangeInfo.days - 1 - i));
    if (d > todayDate) break;
    const ds = d.toISOString().slice(0, 10);
    days.push({ date: ds, vol: dailyVolume[ds] || 0, day: d });
  }

  // Smooth weekly trend (rolling 7-day avg)
  const weeklyTrend = days.map((_, i) => {
    const window = days.slice(Math.max(0, i - 6), i + 1);
    const avg = window.reduce((s, d) => s + d.vol, 0) / window.length;
    return avg;
  });

  // === Per-zone volume + frequency ===
  const ZONE_MAP_LOCAL = {
    chest: "PUSH", front_delt: "PUSH", side_delt: "PUSH", triceps: "PUSH",
    upper_back: "PULL", lats: "PULL", rear_delt: "PULL", traps: "PULL", biceps: "PULL", forearms: "PULL",
    quads: "LEGS", glutes: "LEGS", hamstrings: "LEGS", calves: "LEGS", adductors: "LEGS",
    abs: "CORE", obliques: "CORE", lower_back: "CORE",
  };
  const ZONE_COLORS = { PUSH: "#FF5B3A", PULL: "#3AA8FF", LEGS: "#FFB800", CORE: "#9D6BFF" };

  const zoneStats = React.useMemo(() => {
    const stats = { PUSH: { vol: 0, sets: 0, days: new Set() }, PULL: { vol: 0, sets: 0, days: new Set() }, LEGS: { vol: 0, sets: 0, days: new Set() }, CORE: { vol: 0, sets: 0, days: new Set() } };
    rangeSets.forEach(s => {
      const ex = D.exercises.find(e => e.id === s.exercise);
      if (!ex) return;
      const zones = new Set();
      (ex.primary || []).forEach(m => { if (ZONE_MAP_LOCAL[m]) zones.add(ZONE_MAP_LOCAL[m]); });
      const vol = (s.weight || me.bodyweight || 70) * s.reps;
      zones.forEach(z => {
        stats[z].vol += vol;
        stats[z].sets += 1;
        stats[z].days.add(s.date);
      });
    });
    return Object.entries(stats).map(([k, v]) => ({ zone: k, vol: v.vol, sets: v.sets, days: v.days.size, color: ZONE_COLORS[k] }));
  }, [rangeSets]);

  const totalZoneVol = zoneStats.reduce((s, z) => s + z.vol, 0);

  // === PR Timeline (top lifts progression over time) ===
  const topLifts = ["bb_squat", "bb_deadlift", "bb_bench", "bb_ohp", "pu_pullup", "db_curl"];

  const liftProgression = React.useMemo(() => {
    return topLifts.map(eid => {
      const ex = D.exercises.find(e => e.id === eid);
      if (!ex) return null;
      // Get max weight per workout day for this lift
      const liftSets = rangeSets.filter(s => s.exercise === eid);
      const byDate = {};
      liftSets.forEach(s => {
        // Use 1RM estimate (Epley): w * (1 + reps/30)
        const est1rm = (s.weight || me.bodyweight || 70) * (1 + s.reps / 30);
        byDate[s.date] = Math.max(byDate[s.date] || 0, est1rm);
      });
      const points = Object.entries(byDate).sort().map(([d, v]) => ({ date: d, value: v }));
      const start = points[0]?.value || 0;
      const end = points[points.length - 1]?.value || 0;
      const change = end - start;
      const pctChange = start > 0 ? ((change / start) * 100) : 0;
      return { ex, points, start, end, change, pctChange };
    }).filter(Boolean).filter(l => l.points.length >= 2);
  }, [rangeSets]);

  // === Calendar heatmap (last 6 months always, regardless of range) ===
  const heatmapDays = React.useMemo(() => {
    const out = [];
    const totalDays = 180;
    for (let i = totalDays - 1; i >= 0; i--) {
      const d = new Date(todayDate);
      d.setDate(d.getDate() - i);
      const ds = d.toISOString().slice(0, 10);
      const vol = mySets.filter(s => s.date === ds).reduce((sum, s) => sum + (s.weight || me.bodyweight || 70) * s.reps, 0);
      out.push({ date: ds, vol, day: d });
    }
    return out;
  }, [mySets]);

  const maxHeatVol = Math.max(...heatmapDays.map(d => d.vol), 1);

  // Group heatmap into weeks (columns of 7)
  const heatmapWeeks = [];
  // Start from first Sunday at or before the earliest day
  const firstDay = heatmapDays[0]?.day;
  if (firstDay) {
    const startSun = new Date(firstDay);
    startSun.setDate(startSun.getDate() - startSun.getDay());
    let cur = new Date(startSun);
    while (cur <= todayDate) {
      const week = [];
      for (let dow = 0; dow < 7; dow++) {
        const ds = cur.toISOString().slice(0, 10);
        const found = heatmapDays.find(d => d.date === ds);
        const future = cur > todayDate;
        week.push({
          date: ds,
          vol: found?.vol || 0,
          day: new Date(cur),
          inRange: !!found,
          future
        });
        cur.setDate(cur.getDate() + 1);
      }
      heatmapWeeks.push(week);
    }
  }

  // === Insights ===
  const insights = React.useMemo(() => {
    const out = [];
    // Volume change vs previous period
    const prevCutoff = new Date(cutoffDate);
    prevCutoff.setDate(prevCutoff.getDate() - rangeInfo.days);
    const prevStr = prevCutoff.toISOString().slice(0, 10);
    const prevSets = mySets.filter(s => s.date >= prevStr && s.date < cutoffStr);
    const prevVol = prevSets.reduce((sum, s) => sum + (s.weight || me.bodyweight || 70) * s.reps, 0);
    if (prevVol > 0) {
      const delta = ((totalVolume - prevVol) / prevVol) * 100;
      out.push({
        type: delta > 5 ? "win" : delta < -5 ? "warn" : "info",
        icon: delta > 5 ? "↑" : delta < -5 ? "↓" : "→",
        title: `${delta > 0 ? "+" : ""}${delta.toFixed(1)}% VOLUME`,
        text: delta > 5 ? `You're lifting ${Math.abs(delta).toFixed(0)}% more than the previous ${rangeInfo.days}-day stretch. Keep stacking.` :
              delta < -5 ? `Volume is down ${Math.abs(delta).toFixed(0)}% vs previous ${rangeInfo.days}-day stretch. Recovery week or genuine slip?` :
              `Volume holding steady (±5%) — consistent training pattern.`
      });
    }
    // Imbalance check
    const sortedZones = [...zoneStats].sort((a, b) => b.vol - a.vol);
    if (totalZoneVol > 0) {
      const dominantPct = (sortedZones[0].vol / totalZoneVol) * 100;
      const weakestPct = (sortedZones[3].vol / totalZoneVol) * 100;
      if (dominantPct > 45) {
        out.push({
          type: "warn", icon: "!",
          title: `${sortedZones[0].zone} HEAVY`,
          text: `${sortedZones[0].zone.toLowerCase()} accounts for ${dominantPct.toFixed(0)}% of your volume. Consider rebalancing toward ${sortedZones[3].zone.toLowerCase()} (${weakestPct.toFixed(0)}%).`
        });
      }
    }
    // Consistency
    if (consistencyPct >= 70) {
      out.push({
        type: "win", icon: "★",
        title: `${consistencyPct}% CONSISTENCY`,
        text: `${workoutDays} workout days in the last ${rangeInfo.days}. Top-tier discipline.`
      });
    } else if (consistencyPct < 40 && rangeInfo.days >= 14) {
      out.push({
        type: "warn", icon: "?",
        title: `${consistencyPct}% CONSISTENCY`,
        text: `Only ${workoutDays} workout days in the last ${rangeInfo.days}. Aim for 4+/week for steady progress.`
      });
    }
    // Best lift progression
    const bestLift = [...liftProgression].sort((a, b) => b.pctChange - a.pctChange)[0];
    if (bestLift && bestLift.pctChange > 5) {
      out.push({
        type: "win", icon: "▲",
        title: `${bestLift.ex.name.toUpperCase()} +${bestLift.pctChange.toFixed(1)}%`,
        text: `Estimated 1RM up from ${bestLift.start.toFixed(0)}kg → ${bestLift.end.toFixed(0)}kg over the last ${rangeInfo.days} days.`
      });
    }
    // Weakest lift
    const weakLift = [...liftProgression].filter(l => l.pctChange < 0).sort((a, b) => a.pctChange - b.pctChange)[0];
    if (weakLift) {
      out.push({
        type: "info", icon: "◇",
        title: `${weakLift.ex.name.toUpperCase()} STAGNANT`,
        text: `Estimated 1RM ${weakLift.pctChange < -5 ? "down" : "flat"} ${weakLift.pctChange.toFixed(1)}%. Try varying rep ranges or adding a deload.`
      });
    }
    // PR streak
    if (prsInRange > 0) {
      out.push({
        type: "win", icon: "◆",
        title: `${prsInRange} PRS HIT`,
        text: `${prsInRange} personal record${prsInRange > 1 ? "s" : ""} set in this window. Momentum is real.`
      });
    }
    return out;
  }, [rangeSets, zoneStats, liftProgression, prsInRange]);

  // SVG dimensions
  const chartW = 720, chartH = 200;
  const maxDailyVol = Math.max(...weeklyTrend, ...days.map(d => d.vol), 1);

  // Strongest / favorite exercise
  const exFreq = {};
  rangeSets.forEach(s => { exFreq[s.exercise] = (exFreq[s.exercise] || 0) + 1; });
  const favoriteEx = Object.entries(exFreq).sort((a, b) => b[1] - a[1]).slice(0, 5);

  return (
    <div className="ft-pane jr-pane" style={{ "--c": me.color }}>
      <div className="ft-pane-head">
        <div>
          <div className="ft-pane-title" style={{ color: me.color }}>MY JOURNEY · {me.short}</div>
          <div className="ft-pane-sub">PERSONAL TRAINING ANALYTICS · {rangeInfo.label.toUpperCase()}</div>
        </div>
        <div className="jr-range">
          {Object.keys(ranges).map(r => (
            <button key={r}
              className={`jr-range-btn ${range === r ? "jr-range-btn--on" : ""}`}
              onClick={() => setRange(r)}>
              {r}
            </button>
          ))}
        </div>
      </div>

      {/* HERO STATS */}
      <div className="jr-hero">
        <div className="jr-hero-stat">
          <div className="jr-hero-l">TOTAL VOLUME</div>
          <div className="jr-hero-v">{(totalVolume/1000).toFixed(1)}<span className="jr-hero-u">T</span></div>
          <div className="jr-hero-s">{totalReps.toLocaleString()} REPS</div>
        </div>
        <div className="jr-hero-sep" />
        <div className="jr-hero-stat">
          <div className="jr-hero-l">WORKOUTS</div>
          <div className="jr-hero-v">{workoutDays}<span className="jr-hero-u">/{rangeInfo.days}D</span></div>
          <div className="jr-hero-s">{consistencyPct}% CONSISTENCY</div>
        </div>
        <div className="jr-hero-sep" />
        <div className="jr-hero-stat">
          <div className="jr-hero-l">SETS</div>
          <div className="jr-hero-v">{totalSets}</div>
          <div className="jr-hero-s">{(totalSets / Math.max(workoutDays, 1)).toFixed(1)} AVG/WORKOUT</div>
        </div>
        <div className="jr-hero-sep" />
        <div className="jr-hero-stat">
          <div className="jr-hero-l">PRS</div>
          <div className="jr-hero-v" style={{ color: me.color }}>{prsInRange}</div>
          <div className="jr-hero-s">PERSONAL RECORDS</div>
        </div>
      </div>

      {/* VOLUME TREND CHART */}
      <div className="jr-section">
        <div className="jr-section-head">
          <div className="jr-section-title">VOLUME TREND</div>
          <div className="jr-section-sub">DAILY KG · 7-DAY ROLLING AVERAGE</div>
        </div>
        <svg className="jr-chart" viewBox={`0 0 ${chartW} ${chartH}`} preserveAspectRatio="none">
          {/* gridlines */}
          {[0.25, 0.5, 0.75, 1].map((p, i) => (
            <line key={i} x1="40" y1={chartH - 30 - (chartH - 50) * p} x2={chartW} y2={chartH - 30 - (chartH - 50) * p}
              stroke="rgba(245,241,232,0.08)" strokeDasharray="2 4" />
          ))}
          {/* y-axis labels */}
          {[0.25, 0.5, 0.75, 1].map((p, i) => (
            <text key={i} x="32" y={chartH - 30 - (chartH - 50) * p + 4}
              textAnchor="end" fill="rgba(245,241,232,0.4)" fontSize="9" fontFamily="JetBrains Mono">
              {((maxDailyVol * p) / 1000).toFixed(1)}T
            </text>
          ))}
          {/* daily bars */}
          {days.map((d, i) => {
            const x = 40 + (i / Math.max(days.length - 1, 1)) * (chartW - 50);
            const h = (d.vol / maxDailyVol) * (chartH - 50);
            const barW = Math.max(2, (chartW - 50) / days.length * 0.7);
            return (
              <rect key={i} x={x - barW/2} y={chartH - 30 - h} width={barW} height={h}
                fill="rgba(245,241,232,0.15)" />
            );
          })}
          {/* trend line */}
          <polyline
            points={weeklyTrend.map((v, i) => {
              const x = 40 + (i / Math.max(weeklyTrend.length - 1, 1)) * (chartW - 50);
              const y = chartH - 30 - (v / maxDailyVol) * (chartH - 50);
              return `${x},${y}`;
            }).join(" ")}
            fill="none" stroke={me.color} strokeWidth="2.5" />
          {/* x-axis labels */}
          {[0, 0.25, 0.5, 0.75, 1].map((p, i) => {
            const idx = Math.floor((days.length - 1) * p);
            const d = days[idx]?.day;
            if (!d) return null;
            const x = 40 + p * (chartW - 50);
            const label = `${d.getMonth()+1}/${d.getDate()}`;
            return (
              <text key={i} x={x} y={chartH - 12} textAnchor="middle"
                fill="rgba(245,241,232,0.4)" fontSize="9" fontFamily="JetBrains Mono">
                {label}
              </text>
            );
          })}
        </svg>
      </div>

      {/* ZONE BALANCE + PR PROGRESSION */}
      <div className="jr-grid jr-grid--2">
        <div className="jr-section">
          <div className="jr-section-head">
            <div className="jr-section-title">TRAINING BALANCE</div>
            <div className="jr-section-sub">VOLUME PER ZONE · {totalSets} SETS</div>
          </div>
          <div className="jr-zones">
            {zoneStats.map(z => {
              const pct = totalZoneVol > 0 ? (z.vol / totalZoneVol) * 100 : 0;
              return (
                <div key={z.zone} className="jr-zone">
                  <div className="jr-zone-head">
                    <div className="jr-zone-tag" style={{ background: z.color }}>{z.zone}</div>
                    <div className="jr-zone-stats">
                      <span className="jr-zone-pct" style={{ color: z.color }}>{pct.toFixed(0)}%</span>
                      <span className="jr-zone-sub">{(z.vol/1000).toFixed(1)}T · {z.sets} SETS · {z.days} DAYS</span>
                    </div>
                  </div>
                  <div className="jr-zone-bar">
                    <div className="jr-zone-fill" style={{ width: `${pct}%`, background: z.color }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        <div className="jr-section">
          <div className="jr-section-head">
            <div className="jr-section-title">LIFT PROGRESSION</div>
            <div className="jr-section-sub">EST. 1RM CHANGE · MAJOR LIFTS</div>
          </div>
          <div className="jr-lifts">
            {liftProgression.length === 0 ? (
              <div className="jr-empty">Not enough data in this window. Try a longer range.</div>
            ) : liftProgression.map(l => {
              const isPos = l.change >= 0;
              return (
                <div key={l.ex.id} className="jr-lift">
                  <div className="jr-lift-head">
                    <div className="jr-lift-name">{l.ex.name}</div>
                    <div className={`jr-lift-delta ${isPos ? "jr-lift-delta--pos" : "jr-lift-delta--neg"}`}>
                      {isPos ? "▲" : "▼"} {Math.abs(l.pctChange).toFixed(1)}%
                    </div>
                  </div>
                  <div className="jr-lift-curve">
                    <svg viewBox="0 0 200 40" preserveAspectRatio="none" style={{ width: "100%", height: 40 }}>
                      {l.points.length > 1 && (() => {
                        const min = Math.min(...l.points.map(p => p.value));
                        const max = Math.max(...l.points.map(p => p.value), min + 1);
                        const range = max - min || 1;
                        const pts = l.points.map((p, i) => {
                          const x = (i / (l.points.length - 1)) * 200;
                          const y = 36 - ((p.value - min) / range) * 32;
                          return `${x},${y}`;
                        }).join(" ");
                        const fillPts = `0,40 ${pts} 200,40`;
                        return (
                          <>
                            <polyline points={fillPts} fill={me.color} opacity="0.12" />
                            <polyline points={pts} fill="none" stroke={isPos ? me.color : "#888"} strokeWidth="1.8" />
                          </>
                        );
                      })()}
                    </svg>
                  </div>
                  <div className="jr-lift-num">
                    <span>{l.start.toFixed(0)}KG</span>
                    <span className="jr-lift-arrow">→</span>
                    <span style={{ color: me.color, fontWeight: 800 }}>{l.end.toFixed(0)}KG</span>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>

      {/* CALENDAR HEATMAP — always 6 months */}
      <div className="jr-section">
        <div className="jr-section-head">
          <div className="jr-section-title">CONSISTENCY CALENDAR</div>
          <div className="jr-section-sub">LAST 6 MONTHS · DAILY VOLUME INTENSITY</div>
        </div>
        <div className="jr-heatmap-wrap">
          <div className="jr-heatmap-dows">
            {["", "M", "", "W", "", "F", ""].map((d, i) => (
              <div key={i} className="jr-heatmap-dow">{d}</div>
            ))}
          </div>
          <div className="jr-heatmap-grid">
            {heatmapWeeks.map((week, wi) => (
              <div key={wi} className="jr-heatmap-week">
                {week.map((cell, di) => {
                  const intensity = cell.vol > 0 ? Math.min(1, cell.vol / (maxHeatVol * 0.6)) : 0;
                  const showMonth = di === 0 && cell.day.getDate() <= 7;
                  return (
                    <React.Fragment key={di}>
                      <div className={`jr-heat-cell ${cell.future ? "jr-heat-cell--future" : ""}`}
                        title={`${cell.date} · ${(cell.vol/1000).toFixed(1)}T`}
                        style={{
                          background: cell.vol > 0 ? me.color : "rgba(245,241,232,0.05)",
                          opacity: cell.vol > 0 ? 0.25 + intensity * 0.75 : (cell.future ? 0.1 : 0.4)
                        }} />
                    </React.Fragment>
                  );
                })}
              </div>
            ))}
          </div>
          <div className="jr-heatmap-legend">
            <span>LESS</span>
            {[0, 0.25, 0.5, 0.75, 1].map((p, i) => (
              <div key={i} className="jr-heat-cell jr-heat-cell--legend"
                style={{ background: p === 0 ? "rgba(245,241,232,0.05)" : me.color, opacity: p === 0 ? 0.4 : 0.25 + p * 0.75 }} />
            ))}
            <span>MORE</span>
          </div>
        </div>
      </div>

      {/* INSIGHTS + FAVORITES */}
      <div className="jr-grid jr-grid--2">
        <div className="jr-section">
          <div className="jr-section-head">
            <div className="jr-section-title">INSIGHTS</div>
            <div className="jr-section-sub">AUTO-GENERATED FROM YOUR LOGS</div>
          </div>
          <div className="jr-insights">
            {insights.length === 0 ? (
              <div className="jr-empty">Log more sets to unlock insights.</div>
            ) : insights.map((ins, i) => (
              <div key={i} className={`jr-insight jr-insight--${ins.type}`}>
                <div className="jr-insight-icon">{ins.icon}</div>
                <div className="jr-insight-body">
                  <div className="jr-insight-title">{ins.title}</div>
                  <div className="jr-insight-text">{ins.text}</div>
                </div>
              </div>
            ))}
          </div>
        </div>

        <div className="jr-section">
          <div className="jr-section-head">
            <div className="jr-section-title">MOST-LOGGED LIFTS</div>
            <div className="jr-section-sub">YOUR GO-TO MOVEMENTS</div>
          </div>
          <div className="jr-faves">
            {favoriteEx.length === 0 ? (
              <div className="jr-empty">No data in this window.</div>
            ) : favoriteEx.map(([eid, count], i) => {
              const ex = D.exercises.find(e => e.id === eid);
              const max = favoriteEx[0][1];
              return (
                <div key={eid} className="jr-fave">
                  <div className="jr-fave-rank">#{i+1}</div>
                  <div className="jr-fave-name">{ex?.name || eid}</div>
                  <div className="jr-fave-bar">
                    <div className="jr-fave-fill" style={{ width: `${(count/max)*100}%`, background: me.color }} />
                  </div>
                  <div className="jr-fave-count">{count} SETS</div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
};

window.JourneyView = JourneyView;
