// ranking.jsx — Página dedicada del RANKING (podio + movimientos + tabla completa)
// Autónoma: re-implementa los mismos cálculos que el index para no depender de app.jsx
const { useState, useEffect, useRef } = React;

// ---------- Directorio de pilotos ----------
const RK_DIR = (typeof window !== "undefined" && window.CDG_PILOTS) ? window.CDG_PILOTS : {};
const _RK_NORM = Object.fromEntries(Object.entries(RK_DIR).map(([k, v]) => [k.toLowerCase().trim(), v]));
function pilotMeta(name) { if (!name) return {}; return _RK_NORM[name.toLowerCase().trim()] || {}; }
function flagUrl(code) { return (!code || code.length !== 2) ? "" : `https://flagcdn.com/${code.toLowerCase()}.svg`; }
function pilotHref(name, year, cat) { return `piloto.html?name=${encodeURIComponent(name)}&year=${year}&cat=${encodeURIComponent(cat)}`; }

function parseTime(str) {
  if (!str || typeof str !== "string") return Infinity;
  const m = str.match(/(\d+):(\d+(?:\.\d+)?)/);
  if (!m) return Infinity;
  const ms = parseInt(m[1]) * 60000 + parseFloat(m[2]) * 1000;
  return ms > 0 ? ms : Infinity;
}
function availableYears() {
  const ys = new Set((window.CDG_RESULTS || []).map(r => r.year).filter(Boolean));
  const arr = [...ys].sort((a, b) => b - a);
  if (arr.length === 0) arr.push(new Date().getFullYear());
  return arr;
}

// ---------- Cálculo de standings ----------
function rankRaces(data) {
  const map = new Map();
  const accumulate = (rows, isQual) => {
    rows.forEach(row => {
      const key = (row.handle || row.pilot).toUpperCase();
      const cur = map.get(key) || { name: row.pilot, handle: row.handle || "", points: 0, races: new Set(), bestQual: null, bestBracket: null, qualPts: 0, bracketPts: 0, podiums: 0, wins: 0 };
      const pts = Number(row.points || 0);
      cur.points += pts;
      if (isQual) cur.qualPts += pts; else cur.bracketPts += pts;
      if (row.pos === 1 || row.pos === 2 || row.pos === 3) cur.podiums += 1;
      if (!isQual && row.pos === 1) cur.wins += 1;
      if (row.time) {
        const t = parseTime(row.time);
        if (Number.isFinite(t)) {
          if (isQual && (cur.bestQual === null || t < cur.bestQual.ms)) cur.bestQual = { ms: t, str: row.time };
          if (!isQual && (cur.bestBracket === null || t < cur.bestBracket.ms)) cur.bestBracket = { ms: t, str: row.time };
        }
      }
      map.set(key, cur);
    });
  };
  data.forEach(race => {
    accumulate(race.qualification || [], true);
    accumulate(race.bracket || [], false);
    [...(race.qualification || []), ...(race.bracket || [])].forEach(row => {
      const key = (row.handle || row.pilot).toUpperCase();
      const cur = map.get(key); if (cur) cur.races.add(race.id);
    });
  });
  return [...map.values()].map(p => ({ ...p, racesCount: p.races.size }))
    .sort((a, b) => b.points - a.points || (a.bestQual?.ms ?? Infinity) - (b.bestQual?.ms ?? Infinity));
}
function computeRanking(year, category) {
  return rankRaces((window.CDG_RESULTS || []).filter(r => r.year === year && r.category === category));
}

// ---------- Movimientos vs fecha anterior ----------
const MONTHS_ES = { ENE:0, FEB:1, MAR:2, ABR:3, MAY:4, JUN:5, JUL:6, AGO:7, SEP:8, OCT:9, NOV:10, DIC:11 };
function raceSortKey(race) {
  const d = race.date || ""; let mo = 0, day = 1;
  const mm = d.match(/\b(ENE|FEB|MAR|ABR|MAY|JUN|JUL|AGO|SEP|OCT|NOV|DIC)\b/i);
  if (mm) mo = MONTHS_ES[mm[1].toUpperCase()] || 0;
  const dm = d.match(/\d+/); if (dm) day = parseInt(dm[0], 10);
  return (race.year || 0) * 10000 + mo * 100 + day;
}
function rankingMoves(year, category) {
  const data = (window.CDG_RESULTS || []).filter(r => r.year === year && r.category === category);
  if (data.length < 2) return { moves: {}, lastDate: null };
  const sorted = [...data].sort((a, b) => raceSortKey(a) - raceSortKey(b));
  const maxKey = Math.max(...sorted.map(raceSortKey));
  const prevRaces = sorted.filter(r => raceSortKey(r) < maxKey);
  const lastRace = sorted.find(r => raceSortKey(r) === maxKey);
  if (prevRaces.length === 0) return { moves: {}, lastDate: lastRace?.date || null };
  const cur = rankRaces(sorted), prev = rankRaces(prevRaces);
  const prevPos = {}; prev.forEach((p, i) => { prevPos[(p.handle || p.name).toUpperCase()] = i; });
  const moves = {};
  cur.forEach((p, i) => {
    const key = (p.handle || p.name).toUpperCase(); const pp = prevPos[key];
    if (pp === undefined) moves[key] = { move: "new", amt: 0 };
    else if (pp > i) moves[key] = { move: "up", amt: pp - i };
    else if (pp < i) moves[key] = { move: "down", amt: i - pp };
    else moves[key] = { move: "same", amt: 0 };
  });
  return { moves, lastDate: lastRace?.date || null };
}

// ---------- UI helpers ----------
function PilotAvatar({ name, size, cls }) {
  const meta = pilotMeta(name); const s = size || 54;
  if (meta.photo) return <img className={`pilot-avatar ${cls||""}`} src={meta.photo} alt={name} loading="lazy" style={{ width: s, height: s }} />;
  const initials = String(name || "?").split(/\s+/).map(w => w[0]).slice(0, 2).join("").toUpperCase();
  return <div className={`pilot-avatar pa-fallback ${cls||""}`} style={{ width: s, height: s, fontSize: s * 0.34 }}>{initials}</div>;
}
function MoveIndicator({ info, big }) {
  if (!info) return null;
  const c = big ? "rk-move big" : "rk-move";
  if (info.move === "up") return <span className={`${c} up`} title={`Subió ${info.amt}`}>▲{info.amt > 1 ? <i>{info.amt}</i> : null}</span>;
  if (info.move === "down") return <span className={`${c} down`} title={`Bajó ${info.amt}`}>▼{info.amt > 1 ? <i>{info.amt}</i> : null}</span>;
  if (info.move === "new") return <span className={`${c} new`} title="Nuevo">NEW</span>;
  return <span className={`${c} same`} title="Sin cambios">–</span>;
}
function IgGlyph({ size = 12 }) {
  return (<svg className="ig-ico" viewBox="0 0 24 24" width={size} height={size} aria-hidden="true"><rect x="2.5" y="2.5" width="19" height="19" rx="5.5" fill="none" stroke="currentColor" strokeWidth="2"/><circle cx="12" cy="12" r="4.2" fill="none" stroke="currentColor" strokeWidth="2"/><circle cx="17.3" cy="6.7" r="1.4" fill="currentColor"/></svg>);
}

// Contador animado de puntos (fugacidad)
function useCountUp(target, run) {
  const [val, setVal] = useState(0);
  useEffect(() => {
    if (!run) { setVal(target); return; }
    let raf, start;
    const dur = 900;
    const step = (ts) => {
      if (!start) start = ts;
      const p = Math.min(1, (ts - start) / dur);
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(Math.round(target * eased));
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [target, run]);
  return val;
}

// ---------- Podio ----------
function PodiumCard({ p, place, year, category, mv, animate }) {
  const pts = useCountUp(p.points, animate);
  const meta = pilotMeta(p.name);
  const flag = flagUrl(meta.country);
  const medal = place === 1 ? "ORO" : place === 2 ? "PLATA" : "BRONCE";
  return (
    <a className={`pod-card place-${place} ${category === "TINY" ? "tiny" : ""}`} href={pilotHref(p.name, year, category)} style={{ animationDelay: `${(place === 1 ? 0 : place === 2 ? 0.12 : 0.24)}s` }}>
      <div className="pod-rank">{place}<span className="pod-medal">{medal}</span></div>
      <div className="pod-ava-wrap">
        <PilotAvatar name={p.name} size={place === 1 ? 132 : 104} cls="pod-ava" />
        {mv && <div className="pod-move"><MoveIndicator info={mv} big /></div>}
      </div>
      <div className="pod-name">
        {flag && <img className="rk-flag" src={flag} alt={meta.country} loading="lazy" />}
        {p.name}
      </div>
      {meta.ig
        ? <span className="pod-ig" onClick={(e) => { e.preventDefault(); window.open(`https://instagram.com/${meta.ig}`, "_blank"); }}><IgGlyph />@{meta.ig}</span>
        : <span className="pod-ig none">@—</span>}
      <div className="pod-pts">{pts}<span>pts</span></div>
      <div className="pod-stats">
        <span><b>{p.wins}</b> {p.wins === 1 ? "win" : "wins"}</span>
        <span><b>{p.podiums}</b> {p.podiums === 1 ? "podio" : "podios"}</span>
        <span><b>{p.racesCount}</b> {p.racesCount === 1 ? "fecha" : "fechas"}</span>
      </div>
      <div className="pod-base"></div>
    </a>
  );
}

function Ranking() {
  const years = availableYears();
  const currentYear = new Date().getFullYear();
  const params = new URLSearchParams(location.search);
  const [category, setCategory] = useState(params.get("cat") === "TINY" ? "TINY" : "5\"");
  const [year, setYear] = useState(years.includes(currentYear) ? currentYear : years[0]);
  const [animate, setAnimate] = useState(false);

  useEffect(() => { setAnimate(false); const id = requestAnimationFrame(() => setAnimate(true)); return () => cancelAnimationFrame(id); }, [category, year]);

  const ranking = computeRanking(year, category);
  const { moves, lastDate } = rankingMoves(year, category);
  const catLabel = category === "TINY" ? "Tinywhoop" : "Open 5\"";
  const keyOf = p => (p.handle || p.name).toUpperCase();

  const podium = ranking.slice(0, 3);
  const rest = ranking.slice(3);
  // Orden visual del podio: 2° · 1° · 3°
  const podiumOrder = [podium[1], podium[0], podium[2]].filter(Boolean);

  // Escaladores (mayores subidas) para el strip de movimientos
  const climbers = ranking
    .map((p, i) => ({ p, pos: i + 1, mv: moves[keyOf(p)] }))
    .filter(x => x.mv && (x.mv.move === "up" || x.mv.move === "new"))
    .sort((a, b) => (b.mv.move === "new" ? 1 : b.mv.amt) - (a.mv.move === "new" ? 1 : a.mv.amt))
    .slice(0, 5);

  return (
    <>
      <header className="rk-hero">
        <div className="rk-hero-inner">
          <div className="eyebrow"><span className="num">// RANKING OFICIAL · TEMPORADA {year}{year === currentYear ? " · EN CURSO" : ""}</span></div>
          <h1 className="rk-title">
            {category === "TINY"
              ? <>Ranking<br/><span style={{ color: "#00c2ff" }}>Tiny</span> /26</>
              : <>Ranking<br/><span className="accent">5"</span> /26</>}
          </h1>
          <p className="rk-lead">La pelea por el campeonato del 502, fecha a fecha. Puntos de clasificación + bracket, con los movimientos de cada piloto respecto a la fecha anterior.</p>
          <div className="rk-controls">
            <div className="rk-catwrap">
              <span className="rk-catlabel">Elige categoría · son dos</span>
              <div className="ranking-cat">
                <button className={`rcat-btn ${category === "5\"" ? "active" : ""}`} onClick={() => setCategory("5\"")}>Open 5"<span className="rcat-sub">Full size</span></button>
                <button className={`rcat-btn tiny ${category === "TINY" ? "active" : ""}`} onClick={() => setCategory("TINY")}>Tinywhoop<span className="rcat-sub">Tiny size</span></button>
              </div>
            </div>
            <div className="ranking-year">
              <span className="ry-label">Temporada</span>
              <select value={year} onChange={e => setYear(Number(e.target.value))}>
                {years.map(y => <option key={y} value={y}>{y}{y === currentYear ? " · actual" : ""}</option>)}
              </select>
            </div>
          </div>
        </div>
      </header>

      <main className="rk-main">
        {ranking.length === 0 ? (
          <div className="ranking-empty"><div className="re-icon">—</div><div className="re-text">Sin resultados de {catLabel} para {year}.</div></div>
        ) : (<>
          {/* PODIO */}
          <section className="pod-section">
            <div className="pod-section-head">
              <h2>El podio</h2>
              <span>{catLabel} · {year}</span>
            </div>
            <div key={`${category}-${year}-${animate}`} className={`podium ${animate ? "in" : ""}`}>
              {podiumOrder.map(p => (
                <PodiumCard key={keyOf(p)} p={p} place={ranking.indexOf(p) + 1} year={year} category={category} mv={moves[keyOf(p)]} animate={animate} />
              ))}
            </div>
          </section>

          {/* MOVIMIENTOS */}
          {climbers.length > 0 && (
            <section className="mov-section">
              <div className="mov-head">
                <h3>En racha</h3>
                <span>Mayores subidas{lastDate ? ` · ${lastDate}` : ""}</span>
              </div>
              <div className="mov-strip">
                {climbers.map(({ p, pos, mv }) => (
                  <a className="mov-card" key={keyOf(p)} href={pilotHref(p.name, year, category)}>
                    <PilotAvatar name={p.name} size={46} />
                    <div className="mov-info">
                      <div className="mov-name">{p.name}</div>
                      <div className="mov-meta">P{pos} · {p.points} pts</div>
                    </div>
                    <MoveIndicator info={mv} big />
                  </a>
                ))}
              </div>
            </section>
          )}

          {/* TABLA COMPLETA */}
          <section className="full-section">
            <div className="full-head">
              <h3>Clasificación general</h3>
              <div className="full-legend">
                <span className="rk-move up">▲</span> sube&nbsp;·&nbsp;<span className="rk-move same">–</span> igual&nbsp;·&nbsp;<span className="rk-move down">▼</span> baja
              </div>
            </div>
            <div className="ranking">
              {ranking.map((p, i) => {
                const meta = pilotMeta(p.name); const flag = flagUrl(meta.country); const mv = moves[keyOf(p)];
                return (
                <div className={`ranking-row ${i < 3 ? `podium podium-${i+1}` : ""} ${animate ? "row-in" : ""}`} key={keyOf(p)} style={{ animationDelay: `${Math.min(i, 12) * 0.035}s` }}>
                  <div className="rk-pos">{String(i + 1).padStart(2, "0")}<MoveIndicator info={mv} /></div>
                  <div className="rk-info">
                    <a className="rk-avatar-link" href={pilotHref(p.name, year, category)} title={`Ver ficha de ${p.name}`}>
                      <PilotAvatar name={p.name} size={i === 0 ? 72 : 56} />
                    </a>
                    <div className="rk-text">
                      <div className="rk-handle">
                        {flag && <img className="rk-flag" src={flag} alt={meta.country} loading="lazy" />}
                        {meta.ig
                          ? <a className="rk-ig" href={`https://instagram.com/${meta.ig}`} target="_blank" rel="noopener noreferrer" title="Ver Instagram"><IgGlyph />@{meta.ig}</a>
                          : <span className="rk-ig-none">@—</span>}
                      </div>
                      <div className="rk-name"><a className="rk-name-link" href={pilotHref(p.name, year, category)}>{p.name}<span className="rk-name-arrow" aria-hidden="true">→</span></a></div>
                      <div className="rk-stats">
                        <span><b>{p.racesCount}</b> {p.racesCount === 1 ? "carrera" : "carreras"}</span>
                        <span><b>{p.podiums}</b> {p.podiums === 1 ? "podio" : "podios"}</span>
                        {p.bestQual && <span>Mejor qual <b>{p.bestQual.str}</b></span>}
                      </div>
                    </div>
                  </div>
                  <div className="rk-points">
                    <div className="rk-pts-total">{p.points}</div>
                    <div className="rk-pts-label">Puntos</div>
                    <div className="rk-pts-split">Q {p.qualPts} · B {p.bracketPts}</div>
                  </div>
                </div>
                );
              })}
            </div>
            <div className="full-foot">Clasificación: 1°=35 · 2°=28 · 3°=25 · 4°=22… &nbsp;|&nbsp; Bracket top 4: 6 · 4 · 3 · 2</div>
          </section>
        </>)}
      </main>
    </>
  );
}

ReactDOM.createRoot(document.getElementById("rk-root")).render(<Ranking />);
