/* Standings — season points grid. Drivers & Constructors, season selector. */
const { useState: useSt, useMemo: useStMemo, useEffect: useStEffect } = React;

const CELL_MODE_KEY = "fd.standings.cellMode";
function loadCellMode() {
  try { return localStorage.getItem(CELL_MODE_KEY) === "position" ? "position" : "points"; }
  catch { return "points"; }
}

const VIEW_KEY = "fd.standings.view";
function loadView() {
  try { return localStorage.getItem(VIEW_KEY) === "graph" ? "graph" : "table"; }
  catch { return "table"; }
}

function Segmented({ value, options, onChange }) {
  return (
    <div style={{ display: "inline-flex", background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 10, padding: 3, gap: 2 }}>
      {options.map(o => {
        const on = o.value === value;
        return (
          <button key={o.value} onClick={() => onChange(o.value)} style={{ cursor: "pointer", border: "none",
            fontFamily: "var(--mono)", fontSize: 11.5, letterSpacing: ".1em", textTransform: "uppercase", fontWeight: 600,
            padding: "8px 14px", borderRadius: 8, transition: "all .15s",
            background: on ? "var(--accent)" : "transparent", color: on ? "#fff" : "var(--ink-3)" }}>{o.label}</button>
        );
      })}
    </div>
  );
}

function Legend() {
  const items = [["Win", "var(--accent)"], ["Podium", "color-mix(in srgb, var(--ink) 22%, transparent)"], ["Pole (P)", "var(--warn)"], ["Fastest Lap (F)", "#a855f7"], ["DNF", "transparent"]];
  return (
    <div style={{ display: "flex", gap: 18, flexWrap: "wrap", marginTop: 18 }}>
      {items.map(([lab, c]) => (
        <span key={lab} style={{ display: "inline-flex", alignItems: "center", gap: 7, fontFamily: "var(--mono)", fontSize: 10.5, letterSpacing: ".08em", color: "var(--ink-3)", textTransform: "uppercase" }}>
          <span style={{ width: 13, height: 13, borderRadius: 3, background: c, border: c === "transparent" ? "1px solid var(--line)" : "none" }} />{lab}
        </span>
      ))}
    </div>
  );
}

function cellStyle(o, mode) {
  // o = {pts, pos, dnf}; mode = "points" | "position" (controls displayed text only)
  let bg = "transparent", color = "var(--ink-2)", weight = 500;
  if (o.dnf) return { bg, color: "var(--ink-4)", weight, txt: "DNF", small: true };
  if (o.pos === 1) { bg = "color-mix(in srgb, var(--accent) 26%, transparent)"; color = "var(--ink)"; weight = 800; }
  else if (o.pos <= 3) { bg = "color-mix(in srgb, var(--ink) 9%, transparent)"; color = "var(--ink)"; weight = 700; }
  else if (o.pts > 0) { color = "var(--ink)"; weight = 600; }
  const txt = mode === "position" ? (o.pos ? "P" + o.pos : "–") : (o.pts > 0 ? o.pts : "–");
  return { bg, color, weight, txt, small: false };
}

function DriversGrid({ sid, mode }) {
  const FD = window.FD;
  const sd = FD.seasonData[sid];
  const rounds = sd.byRound;
  const grid = {};
  rounds.forEach(rd => rd.order.forEach(o => { (grid[o.num] = grid[o.num] || {})[rd.rd] = { pts: o.pts, pos: o.pos, dnf: o.dnf, pole: rd.pole === o.num, fastest: !!o.fastest }; }));
  const isS6 = sid === FD.currentSid;
  return (
    <div style={{ overflowX: "auto", border: "1px solid var(--line)", borderRadius: 14, background: "var(--panel)" }}>
      <table style={{ borderCollapse: "collapse", width: "100%", minWidth: 720 }}>
        <thead>
          <tr style={{ borderBottom: "1px solid var(--line)" }}>
            <th style={{ ...thBase, width: 40, textAlign: "center" }}>#</th>
            <th style={{ ...thBase, textAlign: "left", minWidth: 180, position: "sticky", left: 0, background: "var(--panel)", zIndex: 2 }}>Driver</th>
            {rounds.map(rd => (
              <th key={rd.rd} style={{ ...thBase, textAlign: "center", width: 46 }}>
                <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                  {isS6 && <Flag code={FD.races[rd.rd - 1].country} w={18} />}
                  <span>R{rd.rd}</span>
                </div>
              </th>
            ))}
            <th style={{ ...thBase, textAlign: "right", width: 64, color: "var(--ink-2)", position: "sticky", right: 0, background: "var(--panel)", zIndex: 2 }}>Pts</th>
          </tr>
        </thead>
        <tbody>
          {sd.ranked.map((row, i) => {
            const dr = FD.driverByNum[row.num];
            const team = FD.teamById[FD.driverTeam(row.num, sid)];
            return (
              <tr key={row.num} className="fd-grow" style={{ borderBottom: "1px solid var(--line-soft)", cursor: "pointer" }}
                onClick={() => location.href = `driver.html?d=${row.num}`}
                onMouseEnter={e => e.currentTarget.style.background = "color-mix(in srgb, var(--ink) 4%, transparent)"}
                onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
                <td style={{ ...tdBase, textAlign: "center" }}><span className="display" style={{ fontSize: 19, color: i === 0 ? "var(--accent)" : "var(--ink-3)" }}>{i + 1}</span></td>
                <td style={{ ...tdBase, textAlign: "left", position: "sticky", left: 0, background: "var(--panel)", zIndex: 1 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
                    <span style={{ width: 4, height: 30, borderRadius: 2, background: team.color, flex: "none" }} />
                    <Avatar driver={dr} size={32} ring={false} />
                    <div style={{ minWidth: 0 }}>
                      <div style={{ fontFamily: "var(--ui)", fontWeight: 700, fontSize: 14.5, color: "var(--ink)", whiteSpace: "nowrap" }}>{dr.username}</div>
                      <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--ink-4)", letterSpacing: ".06em" }}>{dr.code} · {team.code} · #{dr.num}</div>
                    </div>
                  </div>
                </td>
                {rounds.map(rd => {
                  const o = grid[row.num][rd.rd];
                  if (!o) return <td key={rd.rd} style={{ ...tdBase, textAlign: "center", color: "var(--ink-4)", fontFamily: "var(--mono)", fontSize: 12 }}>·</td>;
                  const cs = cellStyle(o, mode);
                  return (
                    <td key={rd.rd} style={{ ...tdBase, textAlign: "center", padding: 0 }} title={o.dnf ? "DNF" : `P${o.pos} · ${o.pts} pts${o.pole ? " · Pole" : ""}${o.fastest ? " · Fastest Lap" : ""}`}>
                      <div style={{ margin: "4px 3px", padding: "8px 0", borderRadius: 7, background: cs.bg, position: "relative",
                        fontFamily: "var(--mono)", fontVariantNumeric: "tabular-nums", fontWeight: cs.weight,
                        fontSize: cs.small ? 9 : 14, color: cs.color }}>
                        {cs.txt}
                        {o.pole && <span style={{ position: "absolute", top: 1, right: 3, fontSize: 7.5, color: "var(--warn)", fontWeight: 700 }}>P</span>}
                        {o.fastest && <span style={{ position: "absolute", top: 1, left: 3, fontSize: 7.5, color: "#a855f7", fontWeight: 700 }}>F</span>}
                      </div>
                    </td>
                  );
                })}
                <td style={{ ...tdBase, textAlign: "right", position: "sticky", right: 0, background: "var(--panel)", zIndex: 1 }}>
                  <AnimatedNumber value={row.points} duration={900} className="display" style={{ fontSize: 22, color: "var(--ink)" }} />
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

function ConstructorsGrid({ sid }) {
  const FD = window.FD;
  const sd = FD.seasonData[sid];
  const rounds = sd.byRound;
  const standings = FD.teamStandings(sid).filter(t => t.roster.length);
  // team points per round
  const teamRound = (teamId, rd) => rd.order.filter(o => FD.driverTeam(o.num, sid) === teamId).reduce((a, o) => a + o.pts, 0);
  const isS6 = sid === FD.currentSid;
  return (
    <div style={{ overflowX: "auto", border: "1px solid var(--line)", borderRadius: 14, background: "var(--panel)" }}>
      <table style={{ borderCollapse: "collapse", width: "100%", minWidth: 720 }}>
        <thead>
          <tr style={{ borderBottom: "1px solid var(--line)" }}>
            <th style={{ ...thBase, width: 40, textAlign: "center" }}>#</th>
            <th style={{ ...thBase, textAlign: "left", minWidth: 180, position: "sticky", left: 0, background: "var(--panel)", zIndex: 2 }}>Constructor</th>
            {rounds.map(rd => (
              <th key={rd.rd} style={{ ...thBase, textAlign: "center", width: 46 }}>
                <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                  {isS6 && <Flag code={FD.races[rd.rd - 1].country} w={18} />}<span>R{rd.rd}</span>
                </div>
              </th>
            ))}
            <th style={{ ...thBase, textAlign: "right", width: 64, color: "var(--ink-2)", position: "sticky", right: 0, background: "var(--panel)", zIndex: 2 }}>Pts</th>
          </tr>
        </thead>
        <tbody>
          {standings.map((t, i) => (
            <tr key={t.id} className="fd-grow" style={{ borderBottom: "1px solid var(--line-soft)", cursor: "pointer" }}
              onClick={() => location.href = `team.html?t=${t.id}`}
              onMouseEnter={e => e.currentTarget.style.background = "color-mix(in srgb, var(--ink) 4%, transparent)"}
              onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
              <td style={{ ...tdBase, textAlign: "center" }}><span className="display" style={{ fontSize: 19, color: i === 0 ? "var(--accent)" : "var(--ink-3)" }}>{i + 1}</span></td>
              <td style={{ ...tdBase, textAlign: "left", position: "sticky", left: 0, background: "var(--panel)", zIndex: 1 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
                  <TeamLogo team={t} size={26} />
                  <span className="display" style={{ fontSize: 20, color: "var(--ink)", whiteSpace: "nowrap" }}>{t.name}</span>
                  <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "var(--ink-4)" }}>{t.code}</span>
                </div>
              </td>
              {rounds.map(rd => {
                const pts = teamRound(t.id, rd);
                return (
                  <td key={rd.rd} style={{ ...tdBase, textAlign: "center", fontFamily: "var(--mono)", fontVariantNumeric: "tabular-nums",
                    fontSize: 13, color: pts > 0 ? "var(--ink)" : "var(--ink-4)", fontWeight: pts >= 25 ? 700 : 500 }}>{pts > 0 ? pts : "–"}</td>
                );
              })}
              <td style={{ ...tdBase, textAlign: "right", position: "sticky", right: 0, background: "var(--panel)", zIndex: 1 }}>
                <AnimatedNumber value={t.points} duration={900} className="display" style={{ fontSize: 22, color: "var(--ink)" }} />
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

const thBase = { fontFamily: "var(--mono)", fontSize: 10.5, letterSpacing: ".1em", textTransform: "uppercase", color: "var(--ink-4)", fontWeight: 500, padding: "13px 8px" };
const tdBase = { padding: "9px 8px", verticalAlign: "middle" };

// Round a max value up to a clean axis bound (1/2/5 × 10ⁿ).
function niceMax(v) {
  if (v <= 0) return 10;
  const pow = Math.pow(10, Math.floor(Math.log10(v)));
  const n = v / pow;
  const step = n <= 1 ? 1 : n <= 2 ? 2 : n <= 5 ? 5 : 10;
  return step * pow;
}

// Cumulative-points line chart. Pure/dumb: it knows nothing about window.FD.
// series: [{ id, label, color, onClick, cum: [v0, v1, …, vN] }] where cum[0] = 0 (pre-season).
function PointsGraph({ series, roundLabels }) {
  const [hover, setHover] = useSt(null);
  const n = roundLabels.length;
  if (n === 0) {
    return (
      <div style={{ border: "1px solid var(--line)", borderRadius: 14, background: "var(--panel)", padding: "64px 24px", textAlign: "center",
        fontFamily: "var(--mono)", fontSize: 12, letterSpacing: ".08em", textTransform: "uppercase", color: "var(--ink-4)" }}>
        No rounds completed yet
      </div>
    );
  }
  const W = 1000, H = 460, padL = 46, padR = 100, padT = 18, padB = 36;
  const last = s => s.cum[s.cum.length - 1];
  const maxV = niceMax(Math.max(1, ...series.map(last)));
  const x = i => padL + (i / n) * (W - padL - padR);
  const y = v => (H - padB) - (v / maxV) * (H - padB - padT);
  const yTicks = 5;

  // Distinguish series that share a color (e.g. teammates): solid line for the
  // first of each color, dashed variants for the rest.
  const dashPatterns = [null, "7 5", "2 5", "11 5 2 5", "7 5 2 5"];
  const dashById = {};
  const colorSeen = {};
  series.forEach(s => {
    const k = colorSeen[s.color] || 0;
    dashById[s.id] = dashPatterns[k % dashPatterns.length];
    colorSeen[s.color] = k + 1;
  });

  // Declutter end labels: place top-to-bottom, enforce a minimum vertical gap.
  const minGap = 15;
  const ends = series.map(s => ({ id: s.id, color: s.color, label: s.label, v: last(s), ly: y(last(s)) }))
    .sort((a, b) => a.ly - b.ly);
  for (let i = 1; i < ends.length; i++) {
    if (ends[i].ly - ends[i - 1].ly < minGap) ends[i].ly = ends[i - 1].ly + minGap;
  }

  return (
    <div style={{ border: "1px solid var(--line)", borderRadius: 14, background: "var(--panel)", padding: "10px 8px" }}>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: "auto", display: "block" }}
        onMouseLeave={() => setHover(null)}>
        {/* y gridlines + labels */}
        {Array.from({ length: yTicks + 1 }, (_, t) => {
          const v = (maxV * t) / yTicks, yy = y(v);
          return (
            <g key={t}>
              <line x1={padL} y1={yy} x2={W - padR} y2={yy} stroke="var(--line-soft)" strokeWidth="1" />
              <text x={padL - 8} y={yy + 3.5} textAnchor="end" fontFamily="var(--mono)" fontSize="10" fill="var(--ink-4)">{Math.round(v)}</text>
            </g>
          );
        })}
        {/* x round labels */}
        {roundLabels.map((lab, i) => (
          <text key={i} x={x(i + 1)} y={H - padB + 18} textAnchor="middle" fontFamily="var(--mono)" fontSize="10" fill="var(--ink-4)">{lab}</text>
        ))}
        {/* series lines (hit area + visible line + end dot) */}
        {series.map(s => {
          const pts = s.cum.map((v, i) => `${x(i)},${y(v)}`).join(" ");
          const dim = hover && hover !== s.id;
          return (
            <g key={s.id} style={{ cursor: "pointer" }}
              onMouseEnter={() => setHover(s.id)} onClick={s.onClick}>
              <title>{s.label}: {last(s)} pts</title>
              <polyline points={pts} fill="none" stroke="transparent" strokeWidth="14" />
              <polyline points={pts} fill="none" stroke={s.color} strokeLinejoin="round" strokeLinecap="round"
                strokeDasharray={dashById[s.id] || undefined}
                strokeWidth={hover === s.id ? 3.5 : 1.8} style={{ opacity: dim ? 0.12 : 1, transition: "opacity .15s" }} />
              <circle cx={x(n)} cy={y(last(s))} r={hover === s.id ? 4 : 2.6} fill={s.color} style={{ opacity: dim ? 0.12 : 1 }} />
            </g>
          );
        })}
        {/* end labels */}
        {ends.map(e => {
          const dim = hover && hover !== e.id;
          return (
            <text key={e.id} x={x(n) + 8} y={e.ly + 3} fontFamily="var(--mono)" fontSize="10.5"
              fontWeight={hover === e.id ? 700 : 600} fill={e.color}
              style={{ cursor: "pointer", opacity: dim ? 0.18 : 1, transition: "opacity .15s" }}
              onMouseEnter={() => setHover(e.id)} onClick={series.find(s => s.id === e.id).onClick}>{e.label}</text>
          );
        })}
      </svg>
    </div>
  );
}

function driverPointsSeries(FD, sid) {
  const sd = FD.seasonData[sid];
  return sd.ranked.map(row => {
    const dr = FD.driverByNum[row.num];
    const team = FD.teamById[FD.driverTeam(row.num, sid)];
    let acc = 0; const cum = [0];
    sd.byRound.forEach(rd => { const o = rd.order.find(x => x.num === row.num); acc += o ? o.pts : 0; cum.push(acc); });
    return { id: row.num, label: dr.code, color: team.color, onClick: () => location.href = `driver.html?d=${row.num}`, cum };
  });
}

function teamPointsSeries(FD, sid) {
  const sd = FD.seasonData[sid];
  return FD.teamStandings(sid).filter(t => t.roster.length).map(t => {
    let acc = 0; const cum = [0];
    sd.byRound.forEach(rd => { acc += rd.order.filter(o => FD.driverTeam(o.num, sid) === t.id).reduce((a, o) => a + o.pts, 0); cum.push(acc); });
    return { id: t.id, label: t.code, color: t.color, onClick: () => location.href = `team.html?t=${t.id}`, cum };
  });
}

function StandingsPage() {
  const FD = window.FD;
  const [sid, setSid] = useSt(FD.currentSid);
  const [tab, setTab] = useSt("drivers");
  const [cellMode, setCellMode] = useSt(loadCellMode);
  const [view, setView] = useSt(loadView);
  useStEffect(() => { try { localStorage.setItem(CELL_MODE_KEY, cellMode); } catch {} }, [cellMode]);
  useStEffect(() => { try { localStorage.setItem(VIEW_KEY, view); } catch {} }, [view]);
  const season = FD.seasons.find(s => s.id === sid);
  // Graph shows cumulative points, so it's available on Teams (always points) and on
  // Drivers only when the Points cell-mode is selected (per issue #29).
  const graphAvailable = tab === "constructors" || (tab === "drivers" && cellMode === "points");
  const showGraph = graphAvailable && view === "graph";
  const roundLabels = FD.seasonData[sid].byRound.map(rd => "R" + rd.rd);
  return (
    <div style={{ maxWidth: 1280, margin: "0 auto", padding: "48px 36px 90px" }}>
      <PageHead kicker={`${season.label} · ${season.status === "live" ? `Round ${season.completed} of ${season.rounds}` : "Final"}`} title="Standings"
        right={
          <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
            <Segmented value={sid} onChange={setSid} options={FD.seasons.map(s => ({ value: s.id, label: s.label.replace("Season ", "S") }))} />
            <Segmented value={tab} onChange={setTab} options={[{ value: "drivers", label: "Drivers" }, { value: "constructors", label: "Teams" }]} />
            {tab === "drivers" && <Segmented value={cellMode} onChange={setCellMode} options={[{ value: "points", label: "Points" }, { value: "position", label: "Position" }]} />}
            {graphAvailable && <Segmented value={view} onChange={setView} options={[{ value: "table", label: "Table" }, { value: "graph", label: "Graph" }]} />}
          </div>
        } />
      <div key={sid + tab + view}>
        {showGraph
          ? <PointsGraph series={tab === "drivers" ? driverPointsSeries(FD, sid) : teamPointsSeries(FD, sid)} roundLabels={roundLabels} />
          : tab === "drivers" ? <DriversGrid sid={sid} mode={cellMode} /> : <ConstructorsGrid sid={sid} />}
      </div>
      {!showGraph && <Legend />}
      <p style={{ fontFamily: "var(--ui)", fontSize: 13, color: "var(--ink-4)", marginTop: 22, maxWidth: "70ch", lineHeight: 1.5 }}>
        {showGraph
          ? <>Cumulative championship points across the season. Hover a line to highlight it; click for the full profile.</>
          : <>Each cell shows {tab === "drivers" && cellMode === "position" ? "the finishing position" : "points scored"} that round. {season.status === "live" ? `${season.rounds - season.completed} rounds remain this season.` : "Season complete."} Click any row for the full profile.</>}
      </p>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<SiteChrome active="standings"><StandingsPage /></SiteChrome>);
