// Metagraph table — only renders columns we actually have data for.
// As central exposes more per-miner fields, just stop excluding them in
// the column-presence checks below; the table will start rendering them.

window.Metagraph = function Metagraph({ navigate }) {
  // Re-render when data.js finishes its fetch. Until then, show a loading
  // shimmer rather than mock data.
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    const onLoaded = () => setTick((t) => t + 1);
    window.addEventListener('miners:loaded', onLoaded);
    // If data.js already finished before this component mounted, kick once.
    if (window.__MINER_DATA) setTick((t) => t + 1);
    return () => window.removeEventListener('miners:loaded', onLoaded);
  }, []);

  const miners = window.__MINER_DATA || [];
  const summary = window.__MINER_SUMMARY || { total: 0, live: 0, contributions: 0 };

  // Detect which optional columns to render based on what fields the data
  // actually carries. If central later starts returning hotkeys / sparklines /
  // scores, the columns appear automatically with no UI change.
  const hasHotkey = miners.some((m) => !!m.hotkey);
  const hasSparkline = miners.some((m) => Array.isArray(m.sparkline) && m.sparkline.length > 0);
  const hasScore = miners.some((m) => typeof m.score === 'number');

  const [filter, setFilter] = React.useState('all'); // all | live | offline
  const [q, setQ] = React.useState('');

  const filtered = React.useMemo(() => {
    const ql = q.trim().toLowerCase();
    return miners.filter((m) => {
      if (filter === 'live' && !m.live) return false;
      if (filter === 'offline' && m.live) return false;
      if (ql) {
        const searchable = String(m.uid) + (m.hotkey ? ' ' + m.hotkey.toLowerCase() : '');
        return searchable.includes(ql);
      }
      return true;
    });
  }, [q, filter, miners, tick]);

  const maxContrib = miners[0] ? miners[0].contributions : 1;

  function formatLastSeen(h) {
    if (h === null || h === undefined) return 'never';
    if (h < 1) return 'just now';
    if (h < 24) return h + 'h ago';
    const d = Math.floor(h / 24);
    return d + 'd ago';
  }

  // Build column list dynamically. Rank + UID + Contributions + Status are
  // always shown. The rest are conditional on data presence.
  const cols = [
    { key: 'rank', label: 'RANK' },
    { key: 'uid', label: hasHotkey ? 'HOTKEY' : 'UID' },
    { key: 'contributions', label: 'CONTRIBUTIONS' },
  ];
  if (hasSparkline) cols.push({ key: 'spark', label: 'ACTIVITY · 14D', className: 'col-spark' });
  cols.push({ key: 'lastSeen', label: 'LAST CONTRIBUTION', style: { textAlign: 'center' } });
  if (hasScore) cols.push({ key: 'score', label: 'LAST SCORE' });
  cols.push({ key: 'status', label: 'STATUS', style: { textAlign: 'right' } });

  const gridTemplate = cols
    .map((c) => {
      if (c.key === 'rank') return '60px';
      if (c.key === 'uid') return hasHotkey ? '1fr' : '120px';
      if (c.key === 'contributions') return '1.4fr';
      if (c.key === 'spark') return '180px';
      if (c.key === 'lastSeen') return '160px';
      if (c.key === 'score') return '110px';
      if (c.key === 'status') return '120px';
      return '1fr';
    })
    .join(' ');

  return (
    <div className="page">
      <section className="section" style={{paddingTop:16,borderTop:0,paddingBottom:80}}>
        <div className="container">
          <div className="mg-head">
            <div>
              <h2>Metagraph</h2>
              <p style={{color:'var(--fg-dim)',marginTop:10,maxWidth:620,fontSize:15,lineHeight:1.55}}>
                Independent contributors expanding and verifying the Financial Knowledge Graph. Ranked by total accepted contributions; a contributor is <span style={{color:'var(--green)'}}>Live</span> if their most recent contribution landed in the last 7 days.
              </p>
            </div>
            <div className="mg-stats">
              <div>
                <div className="mg-stat-v mono">{summary.total}</div>
                <div className="mg-stat-l">Total contributors</div>
              </div>
              <div>
                <div className="mg-stat-v mono" style={{color:'var(--green)'}}>{summary.live}</div>
                <div className="mg-stat-l">Live (last 7d)</div>
              </div>
              <div>
                <div className="mg-stat-v mono">{(summary.contributions || 0).toLocaleString()}</div>
                <div className="mg-stat-l">Total contributions</div>
              </div>
            </div>
          </div>

          <div className="mg-toolbar">
            <div className="mg-search">
              <Icon name="search" size={15} style={{color:'var(--fg-mute)'}} />
              <input
                placeholder={hasHotkey ? 'Search by UID or hotkey…' : 'Search by UID…'}
                value={q}
                onChange={(e) => setQ(e.target.value)}
              />
            </div>
            <div className="mg-filter">
              <button className={filter==='all'?'on':''} onClick={()=>setFilter('all')}>ALL</button>
              <button className={filter==='live'?'on':''} onClick={()=>setFilter('live')}>LIVE</button>
              <button className={filter==='offline'?'on':''} onClick={()=>setFilter('offline')}>OFFLINE</button>
            </div>
          </div>

          <div className="mg-table">
            <div className="mg-row head" style={{gridTemplateColumns: gridTemplate}}>
              {cols.map((c) => (
                <div key={c.key} className={c.className} style={c.style}>{c.label}</div>
              ))}
            </div>
            {filtered.map((m) => (
              <div className="mg-row body" key={m.uid} style={{gridTemplateColumns: gridTemplate}}>
                <div className="mg-rank">
                  {m.rank <= 3 ? (
                    <span className="top">{m.rank}</span>
                  ) : (
                    <span className="mg-uid" style={{color:'var(--fg-mute)'}}>#{m.rank}</span>
                  )}
                </div>
                <div data-label={hasHotkey ? 'Hotkey' : 'UID'}>
                  {hasHotkey ? (
                    <>
                      <span className="mg-hotkey" title={m.hotkey}>{m.hotkeyShort}</span>
                      <span className="mono" style={{color:'var(--fg-faint)',fontSize:11,marginLeft:10}}>uid:{m.uid}</span>
                    </>
                  ) : (
                    <span className="mono" style={{color:'var(--fg-dim)'}}>UID {m.uid}</span>
                  )}
                </div>
                <div className="mg-bar-wrap" data-label="Contributions">
                  <div className="mg-bar"><div className="mg-bar-fill" style={{width:(m.contributions / maxContrib * 100) + '%'}} /></div>
                  <span className="mg-bar-n">{(m.contributions || 0).toLocaleString()}</span>
                </div>
                {hasSparkline && (
                  <div className="col-spark" data-label="Activity · 14d">
                    <Sparkline data={m.sparkline} live={m.live} />
                  </div>
                )}
                <div className="mono" data-label="Last contribution" style={{color:'var(--fg-dim)',fontSize:13,textAlign:'center'}}>
                  {formatLastSeen(m.lastSeenHoursAgo)}
                </div>
                {hasScore && (
                  <div className="mg-score" data-label="Last score">{m.live ? m.score.toFixed(4) : <span style={{color:'var(--fg-mute)'}}>—</span>}</div>
                )}
                <div data-label="Status" style={{textAlign:'right'}}>
                  {m.live ? (
                    <span className="badge badge-live"><span className="pulse" />LIVE</span>
                  ) : m.lastSeenHoursAgo !== null ? (
                    <span className="badge" title={'last seen ' + formatLastSeen(m.lastSeenHoursAgo)}>IDLE</span>
                  ) : (
                    <span className="badge" style={{color:'var(--fg-mute)'}}>—</span>
                  )}
                </div>
              </div>
            ))}
            {filtered.length === 0 && (
              <div style={{padding:'48px 24px',textAlign:'center',color:'var(--fg-mute)'}}>
                {miners.length === 0 ? 'No contributions recorded yet.' : 'No contributors match.'}
              </div>
            )}
          </div>
        </div>
      </section>
    </div>
  );
};

// Kept for forward compat — when central starts shipping per-miner sparklines,
// the column re-appears and uses this component automatically.
window.Sparkline = function Sparkline({ data, live }) {
  const w = 160, h = 28;
  const max = Math.max(0.0001, ...data);
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * (w - 2) + 1;
    const y = h - 2 - (v / max) * (h - 6);
    return [x, y];
  });
  const path = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
  const areaPath = path + ` L ${w-1} ${h-1} L 1 ${h-1} Z`;
  const color = live ? '#7c7cff' : '#4a4a5a';
  const id = 'sg' + Math.random().toString(36).slice(2, 8);
  return (
    <svg className="mg-spark" viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      <defs>
        <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.4" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={areaPath} fill={`url(#${id})`} />
      <path d={path} fill="none" stroke={color} strokeWidth="1.2" />
      <circle cx={pts[pts.length-1][0]} cy={pts[pts.length-1][1]} r="1.8" fill={color} />
    </svg>
  );
};
