/* ============================================================
   Dashboard Leaderboard — a colorful, sortable season summary
   every member sees on their dashboard. Draws on the SAME data
   as the Season tab (posted weekends + the live current weekend)
   via YCC_SCORING.weekendStats / weekendWins. Pure-CSS/SVG charts.
   ============================================================ */

// Scoring-outcome palette: good (gold/green) → bad (amber/red).
const MIX = [
  { key: "eagles", label: "Eagle", color: "#7a5a22" },
  { key: "birdies", label: "Birdie", color: "#b4904e" },
  { key: "pars", label: "Par", color: "#3a7a4f" },
  { key: "bogeys", label: "Bogey", color: "#6f8f7a" },
  { key: "doubles", label: "Double", color: "#c2743e" },
  { key: "bogeyPlus", label: "Bgy+", color: "#9e3b2f" },
];

// Aggregate every member's season stats (posted weekends + live weekend).
function aggregateSeason(ctx) {
  const Y = window.YCC, ENG = window.YCC_SCORING;
  const { seasonDoc, accountMembers, tour, scores, sideResults, gameConfig, member } = ctx;
  const fullName = (m) => `${m.first_name || ""} ${m.last_name || ""}`.trim() || m.email;
  const postedStats = (seasonDoc && seasonDoc.stats) || {};
  const live = ENG.weekendStats ? ENG.weekendStats({ tour, scores, sideResults, gameConfig }) : {};
  const NUM = ["eagles", "birdies", "pars", "bogeys", "doubles", "bogeyPlus", "holes", "strokes", "toPar", "rounds", "ctp", "longDrive", "wins"];
  const agg = {};
  const blank = () => { const o = { weekendsWon: 0 }; NUM.forEach((k) => (o[k] = 0)); return o; };
  const add = (byName) => Object.entries(byName || {}).forEach(([name, s]) => {
    const a = agg[name] || (agg[name] = blank());
    NUM.forEach((k) => { a[k] += (s[k] || 0); });
    if ((s.wins || 0) > 0) a.weekendsWon += 1;
  });
  Object.values(postedStats).forEach(add);
  const liveIncluded = !postedStats[tour.satISO];
  if (liveIncluded) add(live);

  const hiByName = {};
  (accountMembers || []).forEach((m) => { const n = fullName(m); if (m.handicap_index != null) hiByName[n] = m.handicap_index; });
  if (member && member.name && member.handicapIndex != null && hiByName[member.name] == null) hiByName[member.name] = member.handicapIndex;

  const names = new Set();
  (accountMembers || []).forEach((m) => names.add(fullName(m)));
  Object.keys(agg).forEach((n) => names.add(n));
  if (member && member.name) names.add(member.name);

  const rows = Array.from(names).map((name) => {
    const a = agg[name] || blank();
    const avg = a.holes ? Math.round((a.strokes / a.holes) * 18) : null;
    return {
      name, hi: hiByName[name] != null ? hiByName[name] : null,
      rounds: a.rounds, eagles: a.eagles, birdies: a.birdies, pars: a.pars,
      bogeys: a.bogeys, doubles: a.doubles, bogeyPlus: a.bogeyPlus,
      be: a.birdies + a.eagles, avg, ctp: a.ctp, longDrive: a.longDrive,
      wins: a.wins, weekendsWon: a.weekendsWon, holes: a.holes,
      played: a.holes > 0,
    };
  });
  return { rows, liveIncluded, weeks: Object.keys(postedStats).length };
}

const LB_METRICS = [
  { key: "wins", label: "Wins", icon: "trophy", desc: "Game wins" },
  { key: "avg", label: "Scoring", icon: "target", lowGood: true, desc: "Avg per 18 holes" },
  { key: "eagles", label: "Eagles", icon: "star", desc: "Eagles" },
  { key: "birdies", label: "Birdies", icon: "star", desc: "Birdies" },
  { key: "pars", label: "Pars", icon: "flag", desc: "Pars made" },
  { key: "bogeys", label: "Bogeys", icon: "flag", desc: "Bogeys" },
  { key: "doubles", label: "Doubles", icon: "flag", desc: "Double bogeys" },
  { key: "ctp", label: "Closest", icon: "pin", desc: "Closest-to-pin wins" },
  { key: "longDrive", label: "Long Dr", icon: "trendUp", desc: "Longest-drive wins" },
];

const MEDALS = ["#cba23b", "#aab1ad", "#b9824c"]; // gold, silver, bronze

function initialsOf(n) { return (n || "?").trim().split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase(); }

function DashboardLeaderboard({ ctx }) {
  const { member, go } = ctx;
  const me = member && member.name;
  const { rows, liveIncluded, weeks } = React.useMemo(() => aggregateSeason(ctx), [ctx]);
  const [metricKey, setMetricKey] = React.useState("wins");
  const [grow, setGrow] = React.useState(false);
  const metric = LB_METRICS.find((m) => m.key === metricKey) || LB_METRICS[0];

  // re-animate bars whenever the metric changes
  React.useEffect(() => {
    setGrow(false);
    const t = setTimeout(() => setGrow(true), 40);
    return () => clearTimeout(t);
  }, [metricKey]);

  const val = (r) => r[metric.key];
  // only rank members who have a value for this metric
  const ranked = rows
    .map((r) => ({ ...r, v: val(r) }))
    .filter((r) => r.v != null && (metric.lowGood ? r.played : r.v > 0))
    .sort((a, b) => metric.lowGood ? a.v - b.v : b.v - a.v || a.name.localeCompare(b.name));

  const maxV = ranked.length ? Math.max(...ranked.map((r) => r.v)) : 0;
  const minV = ranked.length ? Math.min(...ranked.map((r) => r.v)) : 0;
  // bar fraction 0..1 — for lowGood, lower is a fuller bar
  const frac = (v) => {
    if (metric.lowGood) {
      if (maxV === minV) return 1;
      return 0.25 + 0.75 * ((maxV - v) / (maxV - minV));
    }
    return maxV ? v / maxV : 0;
  };

  const myRank = ranked.findIndex((r) => r.name === me);
  const myRow = rows.find((r) => r.name === me);

  // podium = top 3, rendered tallest (#1) on the LEFT → shortest on the right
  const podium = ranked.slice(0, 3);
  const podiumOrder = podium;

  const fmtVal = (r) => metric.lowGood ? (r.v == null ? "—" : r.v) : r.v;

  return (
    <div className="card" style={{ overflow: "hidden", marginTop: 4 }}>
      {/* header */}
      <div style={{ background: "linear-gradient(115deg, var(--brand-deep), var(--brand-mid))", color: "var(--on-brand)", padding: "18px var(--card-pad)" }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 14, flexWrap: "wrap" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <div style={{ width: 38, height: 38, borderRadius: 10, background: "color-mix(in srgb, var(--accent) 90%, transparent)", display: "grid", placeItems: "center", color: "#1b1404", flex: "0 0 auto" }}>
              <Icon name="chartBar" size={20} />
            </div>
            <div>
              <h3 className="serif" style={{ fontSize: 21, fontWeight: 600, color: "#fff", lineHeight: 1.05 }}>Season leaderboard</h3>
              <div style={{ fontSize: 12, color: "color-mix(in srgb, var(--on-brand) 78%, transparent)", marginTop: 2 }}>
                {weeks} posted weekend{weeks === 1 ? "" : "s"}{liveIncluded ? " · incl. this weekend live" : ""}
              </div>
            </div>
          </div>
          <button className="btn btn-sm" onClick={() => go("standings")} style={{ background: "color-mix(in srgb, var(--on-brand) 14%, transparent)", color: "#fff", border: "1px solid color-mix(in srgb, var(--on-brand) 26%, transparent)" }}>
            Full season <Icon name="arrowR" size={14} />
          </button>
        </div>
      </div>

      {/* metric selector — cream chip strip, matching the Round history layout */}
      <div style={{ display: "flex", gap: 7, flexWrap: "wrap", padding: "14px var(--card-pad)", borderBottom: "1px solid var(--line)", background: "var(--surface)" }}>
        {LB_METRICS.map((m) => {
          const on = m.key === metricKey;
          return (
            <button key={m.key} onClick={() => setMetricKey(m.key)} title={m.desc}
              style={{
                display: "inline-flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 999,
                fontSize: 12, fontWeight: 700, cursor: "pointer", transition: "all .15s", whiteSpace: "nowrap",
                border: "1px solid " + (on ? "var(--accent)" : "var(--line-strong)"),
                background: on ? "var(--accent)" : "var(--surface)",
                color: on ? "#1b1404" : "var(--ink-soft)",
              }}>
              <Icon name={m.icon} size={12} /> {m.label}
            </button>
          );
        })}
      </div>

      {/* body */}
      <div style={{ display: "grid", gridTemplateColumns: "1.5fr 1fr", gap: 0 }} className="lb-body">
        {/* left: podium + bars */}
        <div style={{ padding: "20px var(--card-pad)", borderRight: "1px solid var(--line)" }} className="lb-left">
          {ranked.length === 0 ? (
            <div style={{ textAlign: "center", padding: "30px 10px", color: "var(--ink-soft)" }}>
              <Icon name="trophy" size={26} style={{ color: "var(--ink-faint)" }} />
              <p style={{ fontSize: 14, marginTop: 10, fontWeight: 600 }}>No {metric.label.toLowerCase()} recorded yet</p>
              <p className="faint" style={{ fontSize: 12.5, marginTop: 4 }}>Stats appear once this weekend's scores are in.</p>
            </div>
          ) : (
            <>
              {/* podium */}
              {podium.length >= 2 && (
                <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "center", gap: 14, marginBottom: 22, paddingTop: 8 }}>
                  {podiumOrder.map((r) => {
                    const place = podium.indexOf(r); // 0,1,2 (left→right, #1 first)
                    // height scales with the value, so equal values = equal bars
                    const h = Math.round(72 + frac(r.v) * 60);
                    const mine = r.name === me;
                    return (
                      <div key={r.name} style={{ flex: "1 1 0", maxWidth: 120, textAlign: "center" }}>
                        <div style={{ position: "relative", display: "inline-block", marginBottom: 9 }}>
                          <div style={{ width: place === 0 ? 56 : 46, height: place === 0 ? 56 : 46, borderRadius: "50%", padding: 3, background: MEDALS[place], margin: "0 auto", boxShadow: place === 0 ? "0 6px 18px -6px " + MEDALS[0] : "none" }}>
                            <Avatar initials={initialsOf(r.name)} size={place === 0 ? 50 : 40} tone={mine ? "accent" : "brand"} />
                          </div>
                          <span style={{ position: "absolute", bottom: -4, right: -2, width: 20, height: 20, borderRadius: "50%", background: MEDALS[place], color: "#fff", fontSize: 11, fontWeight: 800, display: "grid", placeItems: "center", border: "2px solid var(--surface)" }}>{place + 1}</span>
                          {place === 0 && <Icon name="crown" size={20} style={{ color: MEDALS[0], position: "absolute", top: -16, left: "50%", transform: "translateX(-50%)" }} />}
                        </div>
                        <div style={{ fontSize: 12.5, fontWeight: 700, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.name.split(" ")[0]}{mine ? " (you)" : ""}</div>
                        <div className="serif" style={{ fontSize: 19, fontWeight: 700, color: "var(--brand)" }}>{fmtVal(r)}</div>
                        <div style={{ height: h, marginTop: 8, borderRadius: "8px 8px 0 0", background: place === 0 ? "linear-gradient(180deg, var(--accent), var(--accent-deep))" : "linear-gradient(180deg, var(--brand-mid), var(--brand))", transition: "height .6s cubic-bezier(.2,.7,.2,1)", height: grow ? h : 0, display: "grid", placeItems: "start center", paddingTop: 8, color: "color-mix(in srgb, var(--on-brand) 80%, transparent)", fontSize: 11, fontWeight: 700 }}></div>
                      </div>
                    );
                  })}
                </div>
              )}

              {/* ranked bars */}
              <div className="stack" style={{ gap: 9 }}>
                {ranked.slice(0, 8).map((r, i) => {
                  const mine = r.name === me;
                  const pct = Math.max(4, Math.round(frac(r.v) * 100));
                  return (
                    <div key={r.name} style={{ display: "flex", alignItems: "center", gap: 11 }}>
                      <span style={{ width: 18, textAlign: "right", fontSize: 12.5, fontWeight: 700, color: i < 3 ? "var(--accent-deep)" : "var(--ink-faint)", fontVariantNumeric: "tabular-nums" }}>{i + 1}</span>
                      <Avatar initials={initialsOf(r.name)} size={26} tone={mine ? "accent" : "brand"} />
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 8, marginBottom: 3 }}>
                          <span style={{ fontSize: 13, fontWeight: mine ? 800 : 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", color: mine ? "var(--brand)" : "var(--ink)" }}>{r.name}{mine ? " (you)" : ""}</span>
                          <span style={{ fontSize: 13, fontWeight: 800, color: "var(--brand)", fontVariantNumeric: "tabular-nums" }}>{fmtVal(r)}</span>
                        </div>
                        <div style={{ height: 8, borderRadius: 999, background: "var(--surface-2)", overflow: "hidden" }}>
                          <div style={{ height: "100%", borderRadius: 999, width: grow ? pct + "%" : "0%", transition: "width .7s cubic-bezier(.2,.7,.2,1)", transitionDelay: i * 40 + "ms", background: mine ? "linear-gradient(90deg, var(--accent), var(--accent-deep))" : (i === 0 ? "linear-gradient(90deg, var(--brand-mid), var(--brand-deep))" : "var(--brand)") }}></div>
                        </div>
                      </div>
                    </div>
                  );
                })}
              </div>
            </>
          )}
        </div>

        {/* right: your season */}
        <div style={{ padding: "20px var(--card-pad)", background: "var(--surface-2)" }} className="lb-right">
          <div className="eyebrow" style={{ marginBottom: 14 }}>Your season</div>
          <YourSeason myRow={myRow} myRank={myRank} metric={metric} fieldCount={ranked.length} />
        </div>
      </div>

      <style>{`
        @media (max-width: 720px) {
          .lb-body { grid-template-columns: 1fr !important; }
          .lb-left { border-right: none !important; border-bottom: 1px solid var(--line); }
        }
      `}</style>
    </div>
  );
}

function YourSeason({ myRow, myRank, metric, fieldCount }) {
  const played = myRow && myRow.played;
  const mixTotal = played ? MIX.reduce((n, m) => n + (myRow[m.key] || 0), 0) : 0;

  // donut geometry
  const R = 52, C = 2 * Math.PI * R, sw = 16;
  let offset = 0;
  const segs = played && mixTotal ? MIX.map((m) => {
    const v = myRow[m.key] || 0;
    const len = (v / mixTotal) * C;
    const seg = { color: m.color, dash: len, gap: C - len, off: -offset, label: m.label, v };
    offset += len;
    return seg;
  }).filter((s) => s.v > 0) : [];

  const rankText = myRank >= 0 ? `#${myRank + 1}` : "—";

  return (
    <div>
      {/* rank + metric */}
      <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 18 }}>
        <div style={{ width: 62, height: 62, borderRadius: 14, background: myRank === 0 ? "linear-gradient(135deg, var(--accent), var(--accent-deep))" : "var(--brand)", color: "#fff", display: "grid", placeItems: "center", flex: "0 0 auto", boxShadow: "var(--shadow-sm)" }}>
          <span className="serif" style={{ fontSize: 26, fontWeight: 700, lineHeight: 1 }}>{rankText}</span>
        </div>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 700, color: "var(--ink)" }}>{metric.label} rank</div>
          <div className="faint" style={{ fontSize: 12, lineHeight: 1.4 }}>
            {myRank >= 0 ? <>of {fieldCount} ranked · <strong style={{ color: "var(--brand)" }}>{metric.lowGood ? (myRow ? myRow[metric.key] : "—") : (myRow ? myRow[metric.key] : 0)}</strong> {metric.lowGood ? "avg" : metric.label.toLowerCase()}</> : "Not ranked yet for this metric"}
          </div>
        </div>
      </div>

      {/* scoring mix donut */}
      <div style={{ fontSize: 11.5, fontWeight: 700, letterSpacing: ".03em", textTransform: "uppercase", color: "var(--ink-soft)", marginBottom: 10 }}>Scoring mix</div>
      {played && mixTotal ? (
        <div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap" }}>
          <div style={{ position: "relative", width: 140, height: 140, flex: "0 0 auto" }}>
            <svg width="140" height="140" viewBox="0 0 140 140" style={{ transform: "rotate(-90deg)" }}>
              <circle cx="70" cy="70" r={R} fill="none" stroke="var(--surface)" strokeWidth={sw} />
              {segs.map((s, i) => (
                <circle key={i} cx="70" cy="70" r={R} fill="none" stroke={s.color} strokeWidth={sw}
                  strokeDasharray={`${s.dash} ${s.gap}`} strokeDashoffset={s.off} strokeLinecap="butt" />
              ))}
            </svg>
            <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", textAlign: "center" }}>
              <div>
                <div className="serif" style={{ fontSize: 26, fontWeight: 700, color: "var(--brand)", lineHeight: 1 }}>{myRow.holes}</div>
                <div className="faint" style={{ fontSize: 10.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em" }}>holes</div>
              </div>
            </div>
          </div>
          <div style={{ flex: 1, minWidth: 120 }}>
            <div className="stack" style={{ gap: 5 }}>
              {MIX.map((m) => {
                const v = myRow[m.key] || 0;
                if (!v) return null;
                return (
                  <div key={m.key} style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12.5 }}>
                    <span style={{ width: 11, height: 11, borderRadius: 3, background: m.color, flex: "0 0 auto" }}></span>
                    <span style={{ flex: 1, color: "var(--ink-soft)", fontWeight: 600 }}>{m.label}</span>
                    <span style={{ fontWeight: 800, color: "var(--ink)", fontVariantNumeric: "tabular-nums" }}>{v}</span>
                  </div>
                );
              })}
            </div>
          </div>
        </div>
      ) : (
        <div style={{ padding: "18px 0", textAlign: "center", color: "var(--ink-soft)" }}>
          <Icon name="target" size={22} style={{ color: "var(--ink-faint)" }} />
          <p style={{ fontSize: 13, marginTop: 8, fontWeight: 600 }}>No rounds logged yet</p>
          <p className="faint" style={{ fontSize: 12, marginTop: 3 }}>Your scoring mix appears after your first scored round.</p>
        </div>
      )}

      {/* quick stat chips */}
      {played && (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginTop: 18 }}>
          {[["Wins", myRow.wins, "trophy"], ["Birdies+", myRow.be, "star"], ["Rounds", myRow.rounds, "flag"]].map(([lab, v, ic]) => (
            <div key={lab} style={{ background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 10, padding: "10px 8px", textAlign: "center" }}>
              <Icon name={ic} size={14} style={{ color: "var(--accent-deep)" }} />
              <div className="serif" style={{ fontSize: 19, fontWeight: 700, color: "var(--brand)", lineHeight: 1.1, marginTop: 3 }}>{v}</div>
              <div className="faint" style={{ fontSize: 10.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: ".03em" }}>{lab}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { DashboardLeaderboard, aggregateSeason });
