// rankings-clans.jsx — Rankings podium/table + Élite del Ranking (clanes)
const { useState: useStateR, useEffect: useEffectR } = React;

/* ─────────────── Rankings (podium + table) ─────────────── */
function Rankings() {
  const ref = useReveal();
  const [game, setGame] = useStateR('tsbg');
  const [phase, setPhase] = useStateR('all');

  // RANKINGS-WIRED (2026-05-15): consume el endpoint real /inicio/api/public/data
  // que devuelve { members: [...] } con rank/kills/phase/avatar/displayName.
  // Filtramos por phase si seleccionada y mostramos top 10 ordenado por rank.
  const [allMembers, setAllMembers] = useStateR([]);
  useEffectR(() => {
    let cancelled = false;
    const fetchData = async () => {
      try {
        let r = await fetch('api/public/data', { cache: 'no-store' });
        if (!r.ok) r = await fetch('/inicio/api/public/data', { cache: 'no-store' });
        if (!r.ok) return;
        const j = await r.json();
        if (cancelled) return;
        const list = Array.isArray(j.members) ? j.members : (Array.isArray(j) ? j : []);
        setAllMembers(list);
      } catch (_) { /* empty state se muestra */ }
    };
    fetchData();
    const id = setInterval(fetchData, 60_000);
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  // Filtrar por phase si seleccionada, sortear por rank, tomar top 10
  const filtered = allMembers
    .filter(m => phase === 'all' ? true : String(m.phase) === phase.replace('p', ''))
    .filter(m => {
      const r = Number(m.rank);
      return Number.isFinite(r) && r > 0;
    })
    .sort((a, b) => Number(a.rank) - Number(b.rank));

  const top3 = filtered.slice(0, 3).map(m => ({
    rank: Number(m.rank),
    name: m.displayName || m.username || m.nickname || 'Jugador',
    avatar: m.avatar,
    elo: m.elo || (Number(m.kills) > 0 ? `${m.kills}` : '—'),
    phase: m.phase ? `P${m.phase}` : '—',
    kills: Number(m.kills) || 0,
    country: m.country || m.region || (m.phase ? `Phase ${m.phase}` : '—'),
  }));

  const table = filtered.slice(0, 10).map(m => ({
    rank: Number(m.rank),
    name: m.displayName || m.username || m.nickname || 'Jugador',
    avatar: m.avatar,
    elo: m.elo || '—',
    kills: Number(m.kills) || 0,
    winrate: m.winrate || m.winRate || '—',
    phase: m.phase ? `P${m.phase}` : 'P0',
    d: m.delta || m.trend || '—',
  }));

  const phaseColors = {
    P5: { bg: 'color-mix(in srgb, var(--accent) 16%, transparent)', fg: 'var(--accent)' },
    P4: { bg: 'color-mix(in srgb, var(--warn) 16%, transparent)',   fg: 'var(--warn)'   },
    P3: { bg: 'color-mix(in srgb, var(--accent-2) 16%, transparent)', fg: 'var(--accent-2)' },
    P2: { bg: 'color-mix(in srgb, #b06b2c 18%, transparent)', fg: '#d18a4a' },
    P1: { bg: 'color-mix(in srgb, var(--text-muted) 18%, transparent)', fg: 'var(--text-dim)' },
  };

  // GAMES-REAL (2026-05-15): solo juegos que OneWay soporta hoy. NO inventar.
  const games = [
    { id: 'tsb', label: 'TSB' },
    { id: 'jjs', label: 'JJS' },
  ];
  // PHASES-REAL: Phase 0/1 = elite, Phase 5 = base. Filtrar por las mas competitivas.
  const phases = [
    { id: 'all', label: 'Todas' },
    { id: 'p0',  label: 'Phase 0' },
    { id: 'p1',  label: 'Phase 1' },
    { id: 'p2',  label: 'Phase 2' },
  ];

  return (
    <section id="rankings">
      <div className="container">
        <SectionHeader
          eyebrow="02 · Rankings"
          title={<>Compite por <span className="emph">la cima.</span></>}
          subtitle="Datos reales del ranking global, actualizado cada vez que un match termina. Sin estimaciones, sin ELO oculto."
          action={
            <a href="/clans" className="btn btn-ghost" style={{ fontSize: 13 }}>
              Ranking completo
              <Icon.ArrowUpRight size={14}/>
            </a>
          }
        />

        {/* Filters */}
        <div ref={ref} className="reveal" style={{
          display: 'flex', gap: 24, marginTop: 40, marginBottom: 40,
          paddingBottom: 18, borderBottom: '1px solid var(--border)',
          flexWrap: 'wrap', alignItems: 'center',
        }}>
          <FilterGroup label="Juego" value={game} options={games} onChange={setGame}/>
          <div style={{ width: 1, height: 24, background: 'var(--border)' }}/>
          <FilterGroup label="Phase" value={phase} options={phases} onChange={setPhase}/>
          <div style={{ flex: 1 }}/>
          <div className="mono" style={{ fontSize: 11, color: 'var(--text-muted)', letterSpacing: '0.1em', textTransform: 'uppercase', display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--text-muted)' }}/>
            Temporada · por definir
          </div>
        </div>

        {/* Podium */}
        <Podium top3={top3}/>

        {/* Table */}
        <div className="card" style={{ marginTop: 40, overflow: 'hidden' }}>
          <div style={{
            display: 'grid',
            gridTemplateColumns: '60px 1fr 120px 100px 100px 80px 60px',
            gap: 16, alignItems: 'center',
            padding: '14px 20px',
            background: 'var(--surface-2)',
            borderBottom: '1px solid var(--border)',
          }}>
            {['#', 'Jugador', 'ELO', 'Kills', 'Win rate', 'Phase', 'Δ'].map((h, i) => (
              <span key={h} className="mono" style={{
                fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase',
                color: 'var(--text-muted)', textAlign: i === 0 ? 'left' : i === 1 ? 'left' : i >= 2 && i <= 4 ? 'right' : 'center',
              }}>{h}</span>
            ))}
          </div>
          {table.length === 0 && (
            <div style={{ padding: '40px 24px', textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10 }}>
              <div style={{ width: 42, height: 42, borderRadius: 12, background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Icon.Bolt size={20} style={{ color: 'var(--accent)' }}/>
              </div>
              <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>Ranking conectando con el bot</div>
              <div className="mono" style={{ fontSize: 12, color: 'var(--text-muted)', maxWidth: 440, lineHeight: 1.55 }}>
                Las posiciones se reflejan aquí cuando termine el próximo match verificado. Ejecutá <span style={{ color: 'var(--accent)' }}>.leaderboard</span> en Discord para ver el ranking en vivo.
              </div>
            </div>
          )}
          {table.map((p, i) => {
            const ph = phaseColors[p.phase] || phaseColors.P1;
            const wr = (typeof p.winrate === 'number') ? `${p.winrate}%` : (p.winrate || '—');
            const dStr = String(p.d || '—');
            const dColor = dStr.startsWith('+') ? 'var(--live)' : dStr.startsWith('-') ? 'var(--danger)' : 'var(--text-muted)';
            return (
              <div key={`${p.rank}-${p.name}`} style={{
                display: 'grid',
                gridTemplateColumns: '60px 1fr 120px 100px 100px 80px 60px',
                gap: 16, alignItems: 'center',
                padding: '14px 20px',
                borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                transition: 'background .15s',
              }} onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
                 onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                <span className="mono" style={{ fontSize: 13, color: 'var(--text-muted)', fontWeight: 500 }}>{String(p.rank).padStart(2, '0')}</span>
                <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                  {p.avatar ? (
                    <img src={p.avatar} alt={p.name}
                      width="30" height="30"
                      style={{ width: 30, height: 30, borderRadius: '50%', objectFit: 'cover', border: '1px solid var(--border)' }}
                      onError={(e) => { e.currentTarget.style.display = 'none'; }}/>
                  ) : (
                    <div style={{
                      width: 30, height: 30, borderRadius: '50%',
                      background: 'var(--surface-3)', border: '1px solid var(--border)',
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      fontSize: 12, fontWeight: 600, color: 'var(--text-dim)',
                    }}>{(p.name || '?')[0].toUpperCase()}</div>
                  )}
                  <span style={{ fontSize: 14, fontWeight: 500 }}>{p.name}</span>
                </div>
                <span className="mono" style={{ fontSize: 14, color: 'var(--text)', textAlign: 'right', fontWeight: 500 }}>{p.elo}</span>
                <span className="mono" style={{ fontSize: 14, color: 'var(--text-dim)', textAlign: 'right' }}>{Number(p.kills || 0).toLocaleString()}</span>
                <span className="mono" style={{ fontSize: 13, color: 'var(--text-dim)', textAlign: 'right' }}>{wr}</span>
                <span style={{ textAlign: 'center' }}>
                  <span className="mono" style={{
                    display: 'inline-block', padding: '3px 9px', borderRadius: 6,
                    fontSize: 11, fontWeight: 600, letterSpacing: '0.04em',
                    background: ph.bg, color: ph.fg,
                  }}>{p.phase}</span>
                </span>
                <span className="mono" style={{ fontSize: 12, textAlign: 'right', color: dColor }}>{dStr}</span>
              </div>
            );
          })}
          <div style={{
            padding: '14px 20px', textAlign: 'center',
            borderTop: '1px solid var(--border)', background: 'var(--surface-2)',
          }}>
            <a href="/clans" style={{
              fontSize: 13, color: 'var(--text-dim)', textDecoration: 'none',
              display: 'inline-flex', alignItems: 'center', gap: 6,
            }}>
              Ver ranking completo
              <Icon.Arrow size={13}/>
            </a>
          </div>
        </div>
      </div>
    </section>
  );
}

function FilterGroup({ label, value, options, onChange }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
      <span className="mono" style={{ fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--text-muted)' }}>{label}</span>
      <div style={{ display: 'flex', gap: 4, background: 'var(--surface-2)', padding: 4, borderRadius: 9, border: '1px solid var(--border)' }}>
        {options.map(o => {
          const active = o.id === value;
          return (
            <button key={o.id} onClick={() => onChange(o.id)} style={{
              padding: '6px 12px', borderRadius: 6,
              background: active ? 'var(--surface-3)' : 'transparent',
              border: 'none', cursor: 'pointer',
              color: active ? 'var(--text)' : 'var(--text-dim)',
              fontSize: 12, fontWeight: 500, fontFamily: 'inherit',
              transition: 'all .15s',
            }}>{o.label}</button>
          );
        })}
      </div>
    </div>
  );
}

/* Podium with #1 in center elevated, #2 left, #3 right */
function Podium({ top3 }) {
  // Sorted to render order: 2, 1, 3 (already in that order)
  const heights = { 1: 168, 2: 124, 3: 96 };
  const medals = {
    1: { bg: 'linear-gradient(180deg, #FFE186 0%, #B88930 100%)', glow: '#FFCD61', label: 'Campeón' },
    2: { bg: 'linear-gradient(180deg, #D6D9E3 0%, #7A7F8B 100%)', glow: '#C0C4CE', label: 'Subcampeón' },
    3: { bg: 'linear-gradient(180deg, #E0935A 0%, #7B4220 100%)', glow: '#D08456', label: 'Tercer lugar' },
  };

  return (
    <div style={{
      display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
      alignItems: 'end', gap: 14, maxWidth: 720, margin: '0 auto',
      position: 'relative',
    }}>
      {top3.map((p, i) => {
        const m = medals[p.rank];
        const isFirst = p.rank === 1;
        return (
          <div key={p.rank} style={{
            display: 'flex', flexDirection: 'column', alignItems: 'center',
            position: 'relative',
          }}>
            {/* Crown for #1 */}
            {isFirst && (
              <svg width="40" height="28" viewBox="0 0 40 28" style={{ marginBottom: 8, filter: 'drop-shadow(0 4px 12px rgba(255,205,97,0.5))' }}>
                <path d="M4 22l4-14 6 9 6-13 6 13 6-9 4 14H4z" fill="url(#crown-grad)"/>
                <defs>
                  <linearGradient id="crown-grad" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stopColor="#FFE186"/>
                    <stop offset="100%" stopColor="#D9A640"/>
                  </linearGradient>
                </defs>
                <circle cx="20" cy="6" r="2.5" fill="#FFE186"/>
              </svg>
            )}

            {/* Avatar */}
            {p.avatar ? (
              <img src={p.avatar} alt={p.name}
                width={isFirst ? 96 : 72} height={isFirst ? 96 : 72}
                style={{
                  width: isFirst ? 96 : 72, height: isFirst ? 96 : 72,
                  borderRadius: '50%', objectFit: 'cover',
                  border: `2px solid ${m.glow}`,
                  boxShadow: `0 0 0 4px color-mix(in srgb, ${m.glow} 20%, transparent), 0 8px 30px -4px ${m.glow}50`,
                  marginBottom: 14,
                }}
                onError={(e) => { e.currentTarget.style.display = 'none'; }}/>
            ) : (
              <div style={{
                width: isFirst ? 96 : 72, height: isFirst ? 96 : 72,
                borderRadius: '50%',
                background: 'var(--surface-3)',
                border: `2px solid ${m.glow}`,
                boxShadow: `0 0 0 4px color-mix(in srgb, ${m.glow} 20%, transparent), 0 8px 30px -4px ${m.glow}50`,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontWeight: 700, fontSize: isFirst ? 28 : 22, color: 'var(--text-dim)',
                fontFamily: 'Geist Mono',
                marginBottom: 14,
              }}>{(p.name || '?')[0].toUpperCase()}</div>
            )}

            {/* Name */}
            <div style={{ fontSize: isFirst ? 16 : 14, fontWeight: 600, letterSpacing: '-0.01em', textAlign: 'center', minHeight: 38 }}>
              {p.name || 'Jugador'}
              <div className="mono" style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 3, fontWeight: 400 }}>{p.country || '—'} · ELO {p.elo || '—'}</div>
            </div>

            {/* Pedestal */}
            <div style={{
              marginTop: 16, width: '100%',
              height: heights[p.rank],
              background: `linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%)`,
              border: '1px solid var(--border)',
              borderBottom: 'none',
              borderRadius: '12px 12px 0 0',
              position: 'relative',
              display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-start',
              padding: '18px 12px',
              overflow: 'hidden',
            }}>
              {/* Medal */}
              <div style={{
                width: 38, height: 38, borderRadius: '50%',
                background: m.bg,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                color: 'white', fontWeight: 700, fontSize: 14,
                fontFamily: 'Geist Mono',
                boxShadow: `0 4px 12px -2px ${m.glow}80`,
                marginBottom: 10,
              }}>{p.rank}</div>
              <div className="mono" style={{
                fontSize: 9, letterSpacing: '0.14em', textTransform: 'uppercase',
                color: 'var(--text-muted)',
              }}>{m.label}</div>
              <div style={{
                marginTop: 'auto', fontSize: 18, fontWeight: 700, fontFamily: 'Geist Mono',
                background: m.bg, WebkitBackgroundClip: 'text', backgroundClip: 'text', WebkitTextFillColor: 'transparent',
              }}>
                {Number(p.kills || 0).toLocaleString()}
              </div>
              <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', letterSpacing: '0.06em' }}>kills</div>

              {/* Subtle background accent */}
              <div style={{
                position: 'absolute', inset: 0, opacity: 0.06, pointerEvents: 'none',
                background: m.bg,
              }}/>
            </div>
          </div>
        );
      })}
    </div>
  );
}

/* ─────────────── Élite del ranking — clanes ─────────────── */
function ClanesElite() {
  const ref = useReveal();
  // CLANS-WIRED: el endpoint /clans/api/clans del wepage container devuelve la
  // lista enriquecida (con leader info, banner, status). Probamos ese primero
  // — es el único path que llega al handler local de wepage en producción
  // (verificado con route-probe.json: /clans/api/clans → 200 + 29KB JSON,
  // mientras que /inicio/api/public/clans se proxea al bot que devuelve la
  // versión sin leaders enriquecidos).
  const [clans, setClans] = useStateR([]);
  useEffectR(() => {
    let cancelled = false;
    const fetchClans = async () => {
      // Fallback chain — first working URL wins, JSON shape is normalized.
      const urls = [
        '/clans/api/clans',          // wepage-local handler (preferred)
        '/inicio/api/public/clans',  // proxied to bot (basic shape)
        'api/public/clans',          // relative — only works on /inicio/
      ];
      for (const u of urls) {
        try {
          const r = await fetch(u, { cache: 'no-store' });
          if (!r.ok) continue;
          const j = await r.json();
          if (cancelled) return;
          const list = Array.isArray(j) ? j : (Array.isArray(j.clans) ? j.clans : []);
          if (list.length === 0) continue;
          setClans(list);
          return;
        } catch (_) { /* try next URL */ }
      }
    };
    fetchClans();
    const id = setInterval(fetchClans, 60_000);
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  // ── Liveness filter ──────────────────────────────────────────────────────
  // The /clans/api/clans payload retains historical entries after the bot
  // leaves the guild or the clan disbands. Without filtering, dead clans
  // keep their stored `rank` field and show up in Elite forever.
  //
  // A clan is "live" only when ALL of these are true:
  //   1. botActive !== false                         (bot still in guild)
  //   2. memberCount > 0 when the field is numeric   (guild has members)
  //   3. name does NOT match the stale-marker regex  (staff retired marker)
  //   4. asciiized name not in STALE_CLAN_NAMES      (curated blocklist)
  //   5. id not in STALE_CLAN_IDS                    (curated blocklist)
  //
  // Why a curated list: some clans (e.g. "Los Inservibles") still have
  // botActive=null/true in the KV but are gone from the OneWay roster.
  // Staff knows internally but the bot's auto-cleanup hasn't run. The
  // user/staff can add IDs or asciiized names here as they retire clans.
  //
  // asciiize() handles Discord's "fancy" Unicode names (mathematical bold,
  // double-struck, etc.) — NFKD normalization decomposes them to plain
  // letters so "𝐋𝐨𝐬 𝐈𝐧𝐬𝐞𝐫𝐯𝐢𝐛𝐥𝐞𝐬" matches "los inservibles".
  const asciiize = (s) => {
    if (typeof s !== 'string') return '';
    try {
      return s.normalize('NFKD')
              .replace(/[̀-ͯ]/g, '')   // strip combining diacritics
              .toLowerCase()
              .replace(/[^a-z0-9 ]+/g, ' ')      // strip everything not ascii alnum/space
              .replace(/\s+/g, ' ').trim();
    } catch (_) { return String(s).toLowerCase(); }
  };
  const STALE_NAME_RE = /\b\((?:merged|disbanded|dead|inactivo|inactive|cerrado)\)|·\s*ex\b|\bex\s*#\d+/i;
  const STALE_CLAN_NAMES = new Set([
    'los inservibles',          // user-reported 2026-05-16: bot ya no en el guild
  ]);
  const STALE_CLAN_IDS = new Set([
    // Para agregar: id de Discord guild del clan retirado.
  ]);
  const isLiveClan = (c) => {
    if (!c) return false;
    if (c.botActive === false) return false;
    if (typeof c.memberCount === 'number' && c.memberCount <= 0) return false;
    if (typeof c.name === 'string' && STALE_NAME_RE.test(c.name)) return false;
    if (typeof c.name === 'string' && STALE_CLAN_NAMES.has(asciiize(c.name))) return false;
    if (c.id && STALE_CLAN_IDS.has(String(c.id))) return false;
    return true;
  };
  const liveClans = clans.filter(isLiveClan);

  // Elite ranking strategy:
  //   1. If any LIVE clan has a real numeric rank, take the ranked ones first
  //      (sorted by rank ascending) and preserve their stored rank as label.
  //   2. If after the liveness filter we have fewer than 5 ranked clans,
  //      backfill with the largest OFFICIAL clans still alive. This was the
  //      "hueco que falta" reported by the user — Los Inservibles (#4) +
  //      Eclipse merged (#25) got dropped, leaving 4 cards instead of 5.
  //      Backfilled entries are labeled "—" (no real rank, just a featured slot).
  //   3. If no clan has any rank at all, synthesize ranks 1..5 from the top 5
  //      official clans by memberCount.
  const ranked = liveClans
    .filter(c => Number.isFinite(Number(c.rank)) && Number(c.rank) > 0)
    .sort((a, b) => Number(a.rank) - Number(b.rank));
  const hasRealRanks = ranked.length > 0;

  let eliteSource;
  if (hasRealRanks) {
    const seenIds = new Set();
    const out = [];
    // First pass: ranked LIVE clans
    for (const c of ranked.slice(0, 5)) {
      out.push({ ...c, __rank: Number(c.rank), __synthetic: false });
      if (c.id) seenIds.add(String(c.id));
      if (c.name) seenIds.add(String(c.name));
    }
    // Backfill: largest officials not already in the list
    if (out.length < 5) {
      const backfillPool = liveClans
        .filter(c => (c.status || 'community') === 'official')
        .filter(c => !seenIds.has(String(c.id)) && !seenIds.has(String(c.name)))
        .sort((a, b) => (Number(b.memberCount) || 0) - (Number(a.memberCount) || 0));
      for (const c of backfillPool) {
        if (out.length >= 5) break;
        out.push({ ...c, __rank: null, __synthetic: true });
      }
    }
    eliteSource = out;
  } else {
    eliteSource = liveClans
      .filter(c => (c.status || 'community') === 'official')
      .sort((a, b) => (Number(b.memberCount) || 0) - (Number(a.memberCount) || 0))
      .slice(0, 5)
      .map((c, i) => ({ ...c, __rank: i + 1, __synthetic: true }));
  }

  // The /clans/api/clans endpoint ships staff in two fields:
  //   · c.leader   — the primary leader (string OR {displayName, ...} object)
  //   · c.leaders  — array of all directive staff (objects with .displayName,
  //                  .username, .avatar, .id) — same shape /clans page uses
  //
  // The previous EliteCard only displayed the primary as "Líder · X", which is
  // wrong when a clan has multiple founders/co-leaders (e.g. Zero Hex: 4.yin,
  // ijezko, _luar_la_l_). Now we collect ALL display names, dedupe, and pass
  // an array to the card so it can render the full staff list.
  const leaderName = (l) => {
    if (!l) return null;
    if (typeof l === 'string') return l.trim() || null;
    return l.displayName || l.username || l.tag || l.name || null;
  };
  const leaderAvatar = (l) => {
    if (!l || typeof l !== 'object') return null;
    return l.avatar || l.avatarUrl || null;
  };
  const collectStaff = (c) => {
    const out = [];
    const seen = new Set();
    const push = (l) => {
      const name = leaderName(l);
      if (!name) return;
      const key = name.toLowerCase();
      if (seen.has(key)) return;
      seen.add(key);
      out.push({ name, avatar: leaderAvatar(l), id: (l && typeof l === 'object' && l.id) || null });
    };
    if (Array.isArray(c.leaders)) c.leaders.forEach(push);
    push(c.leader);
    return out;
  };

  const eliteWired = eliteSource.map(c => {
    const staff = collectStaff(c);
    return {
      rank: c.__rank,
      synthetic: Boolean(c.__synthetic),
      tag: String(c.id || c.name || '?').slice(-3).toUpperCase(),
      name: c.name || 'Clan',
      logo: c.logo || c.logoUrl || null,
      banner: c.banner || c.bannerUrl || null,
      members: c.memberCount || 0,
      staff,                             // [{name, avatar, id}, ...]
      isChamp: c.__rank === 1,
      elo: c.averageRank || '—',
      wr: c.winRate || '—',
    };
  });

  // Directory = the rest. If we used member-count-based elite, exclude those
  // IDs from the directory so the same clan doesn't appear twice. Also runs
  // through the same liveness filter so dead/merged clans never leak in here.
  const eliteIds = new Set(eliteSource.map(c => String(c.id || c.name)));
  const directoryWired = liveClans
    .filter(c => !eliteIds.has(String(c.id || c.name)))
    .slice(0, 12)
    .map(c => ({
      id: c.id,
      tag: String(c.id || c.name || '?').slice(-3).toUpperCase(),
      name: c.name || 'Clan',
      logo: c.logo || c.logoUrl || null,
      members: c.memberCount || 0,
      status: c.status || 'community',
      leader: leaderName(c.leader),
    }));

  const tr = (window.OW_useT ? window.OW_useT() : (k) => k);
  return (
    <section id="clanes" style={{ background: 'var(--surface)', borderTop: '1px solid var(--border)', borderBottom: '1px solid var(--border)' }}>
      <div className="container">
        <SectionHeader
          eyebrow={tr('sec.clanes.eyebrow')}
          title={<>{tr('sec.clanes.title.a')} <span className="emph">{tr('sec.clanes.title.b')}</span></>}
          subtitle={tr('sec.clanes.sub')}
          action={
            <a href={(typeof window !== 'undefined' && window.OW_INVITE_SERVER) || 'https://discord.gg/zaPG9adRmq'} target="_blank" rel="noopener noreferrer" className="btn btn-ghost" style={{ fontSize: 13 }}>
              {tr('sec.clanes.register')}
              <Icon.Arrow size={14}/>
            </a>
          }
        />

        {/* Top 5 elite */}
        <div ref={ref} className="reveal" style={{ marginTop: 48 }}>
          <div className="mono" style={{
            fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase',
            color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 10,
            marginBottom: 18,
          }}>
            <span style={{ width: 2, height: 14, background: 'var(--accent)' }}/>
            Élite del ranking
          </div>

          {eliteWired.length === 0 ? (
            <div style={{
              padding: '40px 28px', textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10,
              background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 14,
            }}>
              <div style={{ width: 42, height: 42, borderRadius: 12, background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Icon.Trophy size={20} style={{ color: 'var(--accent)' }}/>
              </div>
              <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>Ranking aún en formación</div>
              <div className="mono" style={{ fontSize: 12, color: 'var(--text-muted)', maxWidth: 460, lineHeight: 1.55 }}>
                Los 5 clanes top aparecen acá cuando completen su primera temporada verificada. Mientras tanto, registrá tu clan con <span style={{ color: 'var(--accent)' }}>.clan register</span> en Discord.
              </div>
            </div>
          ) : (
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 14,
            }} id="elite-grid">
              {eliteWired.map(c => <EliteCard key={c.tag + c.rank} c={c}/>)}
            </div>
          )}
        </div>

        {/* Global directory */}
        <div style={{ marginTop: 64 }}>
          <div className="mono" style={{
            fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase',
            color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 10,
            marginBottom: 18,
          }}>
            <span style={{ width: 2, height: 14, background: 'var(--accent)' }}/>
            Directorio global de clanes
          </div>
          {directoryWired.length === 0 ? (
            <div style={{
              padding: '32px 24px', textAlign: 'center',
              background: 'var(--surface-2)', border: '1px dashed var(--border)', borderRadius: 14,
              color: 'var(--text-dim)', fontSize: 13, lineHeight: 1.55,
            }}>
              El directorio público se llena con los clanes verificados manualmente. Pasá por <a href="/clans" style={{ color: 'var(--accent)', textDecoration: 'none' }}>oneway.lat/clans</a> para ver el listado vivo.
            </div>
          ) : (
            <>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14 }} id="dir-grid">
                {directoryWired.map(c => <DirCard key={c.tag + (c.name || '')} c={c}/>)}
              </div>
              <div style={{ marginTop: 20, textAlign: 'center' }}>
                <a href="/clans" style={{
                  fontSize: 13, color: 'var(--text-dim)', textDecoration: 'none',
                  display: 'inline-flex', alignItems: 'center', gap: 6,
                }}>
                  Ver los {clans.length} clanes registrados
                  <Icon.Arrow size={13}/>
                </a>
              </div>
            </>
          )}
        </div>
      </div>
      <style>{`
        @media (max-width: 1100px) { #elite-grid { grid-template-columns: repeat(3, 1fr) !important; } #dir-grid { grid-template-columns: repeat(2, 1fr) !important; } }
        @media (max-width: 700px) { #elite-grid { grid-template-columns: repeat(2, 1fr) !important; } #dir-grid { grid-template-columns: 1fr !important; } }
        @media (max-width: 460px) { #elite-grid { grid-template-columns: 1fr !important; } }
      `}</style>
    </section>
  );
}

/* EliteCard simplificada: usa c.logo real del CDN Discord + name + rank + members.
   Si c.synthetic, el slot es un backfill (no tiene rank real, lo mostramos como
   "Destacado" en var(--accent-2) sin badge dorado de champion). */
function EliteCard({ c }) {
  const rankColors = { 1: 'var(--warn)', 2: 'var(--text-dim)', 3: '#FF7340', 4: 'var(--accent)', 5: 'var(--accent-2)' };
  const rankColor = c.synthetic ? 'var(--accent-2)' : (rankColors[c.rank] || 'var(--accent)');
  const isChamp = !c.synthetic && (c.isChamp || c.rank === 1);
  const labelText = isChamp
    ? 'Campeón'
    : (c.synthetic || !Number.isFinite(Number(c.rank))
        ? 'Destacado'
        : `Rank #${c.rank}`);

  return (
    <article style={{
      background: 'var(--surface-2)',
      border: isChamp ? `1px solid color-mix(in srgb, var(--warn) 40%, var(--border))` : '1px solid var(--border)',
      borderRadius: 16, overflow: 'hidden',
      transition: 'transform .25s ease, border-color .25s ease, box-shadow .25s ease',
      display: 'flex', flexDirection: 'column', position: 'relative',
    }}
    onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-3px)'; e.currentTarget.style.boxShadow = 'var(--shadow-lg)'; e.currentTarget.style.borderColor = isChamp ? 'var(--warn)' : 'var(--border-strong)'; }}
    onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.borderColor = isChamp ? `color-mix(in srgb, var(--warn) 40%, var(--border))` : 'var(--border)'; }}>
      {/*
        Banner layer.  Priority: explicit guild banner -> logo-as-backdrop
        (blurred + dimmed, same trick /clans uses) -> last-resort gradient
        with subtle warm/cool variant for champion vs. others.  Avoids the
        flat blue plate that everyone complained about.
      */}
      <div style={{
        height: 120, position: 'relative',
        background: '#0B1330', // base color while the image loads
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        overflow: 'hidden',
      }}>
        {/* Backdrop layer (z=0): banner if provided, else logo-as-banner, else gradient */}
        {c.banner ? (
          <img src={c.banner} alt="" aria-hidden="true"
            onError={(e) => { e.currentTarget.style.display = 'none'; }}
            style={{
              position: 'absolute', inset: 0, width: '100%', height: '100%',
              objectFit: 'cover', filter: 'brightness(0.78) saturate(1.05)',
              zIndex: 0,
            }}/>
        ) : c.logo ? (
          <img src={c.logo} alt="" aria-hidden="true"
            onError={(e) => { e.currentTarget.style.display = 'none'; }}
            style={{
              position: 'absolute', inset: 0, width: '100%', height: '100%',
              objectFit: 'cover',
              transform: 'scale(1.18)',
              filter: 'blur(18px) brightness(0.5) saturate(1.1)',
              zIndex: 0,
            }}/>
        ) : (
          <div style={{
            position: 'absolute', inset: 0, zIndex: 0,
            background: isChamp
              ? 'linear-gradient(135deg, #B88930 0%, #1A1E5C 100%)'
              : 'linear-gradient(135deg, #1A1E5C 0%, #2A3680 100%)',
          }}/>
        )}
        {/* Overlay (z=1): legibility scrim, slightly warmer on champion */}
        <div style={{
          position: 'absolute', inset: 0, zIndex: 1,
          background: isChamp
            ? 'linear-gradient(180deg, rgba(0,0,0,0.10) 0%, rgba(0,0,0,0.55) 100%)'
            : 'linear-gradient(180deg, rgba(8,9,12,0.15) 0%, rgba(8,9,12,0.65) 100%)',
          pointerEvents: 'none',
        }}/>
        {/* Foreground logo or tag (z=2) */}
        {c.logo ? (
          <img src={c.logo} alt={c.name}
            width="72" height="72"
            style={{ width: 72, height: 72, borderRadius: 16, objectFit: 'cover', border: '2px solid rgba(255,255,255,0.22)', boxShadow: '0 10px 24px -6px rgba(0,0,0,0.6)', position: 'relative', zIndex: 2 }}
            onError={(e) => { e.currentTarget.style.display = 'none'; }}/>
        ) : (
          <div style={{
            width: 72, height: 72, borderRadius: 16,
            background: 'rgba(255,255,255,0.1)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: 'white', fontWeight: 700, fontSize: 18, fontFamily: 'Geist Mono', letterSpacing: '0.04em',
            position: 'relative', zIndex: 2,
          }}>{c.tag}</div>
        )}
      </div>
      <div style={{ padding: '18px 14px 16px', textAlign: 'center', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div className="mono" style={{
          fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase',
          color: rankColor, fontWeight: 600,
          display: 'inline-flex', alignItems: 'center', gap: 6, justifyContent: 'center',
        }}>
          {isChamp && <Icon.Trophy size={12}/>}
          {!isChamp && c.synthetic && <Icon.Sparkle size={12}/>}
          {labelText}
        </div>
        <div style={{ fontSize: 14, fontWeight: 600, marginTop: 8, letterSpacing: '-0.01em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
          {c.name}
        </div>
        {/* Member counter */}
        <div style={{
          marginTop: 12, padding: '8px 0',
          background: 'var(--surface-3)', border: '1px solid var(--border)', borderRadius: 8,
          display: 'flex', justifyContent: 'center', gap: 4, alignItems: 'baseline',
        }}>
          <span className="mono" style={{ fontSize: 16, fontWeight: 700, color: 'var(--text)' }}>{Number(c.members || 0).toLocaleString()}</span>
          <span className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', letterSpacing: '0.1em', textTransform: 'uppercase' }}>miembros</span>
        </div>
        {/* Staff directivo — same data /clans page uses for STAFF DIRECTIVO chips */}
        {Array.isArray(c.staff) && c.staff.length > 0 && (
          <div style={{ marginTop: 14, textAlign: 'left' }}>
            <div className="mono" style={{
              fontSize: 9, letterSpacing: '0.14em', textTransform: 'uppercase',
              color: 'var(--text-muted)', fontWeight: 700, marginBottom: 8, textAlign: 'center',
            }}>
              Staff directivo
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {c.staff.slice(0, 3).map((s, idx) => (
                <div key={(s.id || s.name) + '-' + idx} style={{
                  display: 'grid', gridTemplateColumns: '22px 1fr', gap: 8, alignItems: 'center',
                  padding: '5px 8px',
                  background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 7,
                }}>
                  {s.avatar ? (
                    <img src={s.avatar} alt={s.name} width="22" height="22"
                      referrerPolicy="no-referrer"
                      style={{ width: 22, height: 22, borderRadius: '50%', objectFit: 'cover', border: '1px solid var(--border)' }}
                      onError={(e) => { e.currentTarget.style.visibility = 'hidden'; }}/>
                  ) : (
                    <div style={{
                      width: 22, height: 22, borderRadius: '50%',
                      background: 'var(--surface-3)', border: '1px solid var(--border)',
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      fontSize: 9, fontWeight: 700, color: 'var(--text-dim)',
                    }}>{(s.name || '?')[0].toUpperCase()}</div>
                  )}
                  <span style={{ fontSize: 11, color: 'var(--text-dim)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                    {s.name}
                  </span>
                </div>
              ))}
              {c.staff.length > 3 && (
                <div className="mono" style={{ fontSize: 9, color: 'var(--text-muted)', textAlign: 'center', marginTop: 2 }}>
                  + {c.staff.length - 3} más
                </div>
              )}
            </div>
          </div>
        )}
      </div>
    </article>
  );
}

function DirCard({ c }) {
  const statusColors = {
    official: { bg: 'color-mix(in srgb, var(--accent) 14%, transparent)', fg: 'var(--accent)', label: 'OFICIAL' },
    community: { bg: 'color-mix(in srgb, var(--text-muted) 14%, transparent)', fg: 'var(--text-dim)', label: 'COMUNIDAD' },
    allied: { bg: 'color-mix(in srgb, var(--live) 14%, transparent)', fg: 'var(--live)', label: 'ALIADO' },
  };
  const s = statusColors[c.status] || statusColors.community;
  return (
    <article style={{
      background: 'var(--surface-2)', border: '1px solid var(--border)',
      borderRadius: 14, overflow: 'hidden', display: 'flex', flexDirection: 'column',
      transition: 'transform .2s, border-color .2s',
    }}
    onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.borderColor = 'var(--border-strong)'; }}
    onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.borderColor = 'var(--border)'; }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 14px 12px' }}>
        {c.logo ? (
          <img src={c.logo} alt={c.name} width="42" height="42"
            style={{ width: 42, height: 42, borderRadius: 10, objectFit: 'cover', border: '1px solid var(--border)' }}
            onError={(e) => { e.currentTarget.style.display = 'none'; }}/>
        ) : (
          <div style={{
            width: 42, height: 42, borderRadius: 10,
            background: 'var(--surface-3)', border: '1px solid var(--border)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: 'var(--text-dim)', fontWeight: 700, fontSize: 12, fontFamily: 'Geist Mono',
          }}>{c.tag}</div>
        )}
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-0.01em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.name}</div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{c.leader ? `Líder · ${c.leader}` : '—'}</div>
        </div>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 14px 14px' }}>
        <span className="mono" style={{
          fontSize: 9, padding: '3px 8px', borderRadius: 999, letterSpacing: '0.1em',
          background: s.bg, color: s.fg,
        }}>{s.label}</span>
        <span style={{ fontSize: 11, color: 'var(--text-dim)' }}>
          <span className="mono" style={{ fontWeight: 600, color: 'var(--text)' }}>{Number(c.members || 0).toLocaleString()}</span> <span style={{ color: 'var(--text-muted)' }}>mbr</span>
        </span>
      </div>
    </article>
  );
}

Object.assign(window, { Rankings, ClanesElite });
