/**
 * llmindex.io — live leaderboard: polls scores + benchmark progress, updates in place
 * Author:  Simon-Pierre Boucher
 * Contact: contact@spboucher.ai
 * License: Proprietary — © Simon-Pierre Boucher, all rights reserved
 *
 * Results appear gradually, one model at a time, as the online benchmark
 * finishes each model and the IRT refit publishes a new score run.
 */
'use client';

import { useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { DemoBanner, ScoreBar, ScoreValue, formatMs, formatUsd } from '@llmindex/ui';
import { ProviderLogo } from './ProviderLogo';

export interface ApiEntry {
  rank: number;
  model: string;
  name: string;
  provider: string;
  score: number;
  score_low: number;
  score_high: number;
  sub_metrics?: Record<string, number | null> | null;
}

export interface ApiRun {
  id: string;
  kind: string;
  status: string;
  created_at: string;
  notes?: string | null;
}

interface Progress {
  active: boolean;
  models?: string[];
  completed?: string[];
  failed?: string[];
  current?: {
    model: string;
    domain: string;
    domain_index: number;
    domains_total: number;
    calls_done: number;
    calls_total: number;
  } | null;
  currents?: Array<NonNullable<Progress['current']>>;
  note?: string;
}

export interface LiveLeaderboardProps {
  domain?: string;
  initialRun: ApiRun | null;
  initialEntries: ApiEntry[];
  indexVersion: string;
}

const POLL_MS = 5000;

function ProgressBanner({ progress }: { progress: Progress }) {
  const total = progress.models?.length ?? 0;
  const nDone = progress.completed?.length ?? 0;
  const nFailed = progress.failed?.length ?? 0;
  const done = nDone + nFailed;
  const overallPct = total > 0 ? Math.round((100 * done) / total) : 0;
  const lanes =
    progress.currents && progress.currents.length > 0
      ? progress.currents
      : progress.current
        ? [progress.current]
        : [];
  const runningModels = new Set(lanes.map((l) => l.model)).size;
  const recent = (progress.completed ?? []).slice(-5).reverse();
  const remaining = Math.max(0, total - done - runningModels);

  return (
    <div className="overflow-hidden rounded-2xl border border-emerald-200 bg-gradient-to-br from-emerald-50 via-white to-cyan-50">
      {/* header */}
      <div className="flex flex-wrap items-center gap-x-4 gap-y-2 px-4 py-3 sm:px-5">
        <span className="flex items-center gap-2 text-sm font-semibold text-emerald-700">
          <span className="relative flex h-2.5 w-2.5">
            <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-60" />
            <span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-emerald-400" />
          </span>
          Live benchmark
        </span>
        <span className="text-xs text-zinc-600">
          <span className="font-semibold text-zinc-900 tabular-nums">{done}</span>
          <span className="text-zinc-500">/{total} models</span>
          {nFailed > 0 && <span className="ml-2 text-red-400">{nFailed} failed</span>}
        </span>
        <span className="ml-auto text-2xl font-bold tabular-nums text-zinc-900">{overallPct}%</span>
      </div>
      {/* overall bar */}
      <div className="h-1 w-full bg-zinc-100">
        <div
          className="h-1 bg-gradient-to-r from-emerald-500 to-cyan-500 transition-all duration-700"
          style={{ width: `${overallPct}%` }}
        />
      </div>

      {/* active evaluation lanes (parallel) */}
      {lanes.length > 0 && (
        <div className="divide-y divide-zinc-100">
          {lanes.map((lane, i) => {
            const pct = lane.calls_total > 0 ? Math.round((100 * lane.calls_done) / lane.calls_total) : 0;
            return (
              <div key={`${lane.model}-${lane.domain}-${i}`} className="flex items-center gap-3 px-4 py-2.5 sm:px-5">
                <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-zinc-200 bg-white">
                  <ProviderLogo provider={lane.model.split('/')[0] ?? ''} size={20} />
                </div>
                <div className="min-w-0 flex-1">
                  <div className="flex flex-wrap items-baseline gap-x-2.5 gap-y-0.5">
                    <span className="truncate text-[13px] font-semibold text-zinc-900">
                      {lane.model.split('/')[1] ?? lane.model}
                    </span>
                    <span className="text-[11px] capitalize text-cyan-700">
                      {lane.domain.replaceAll('_', ' ')}
                    </span>
                    <span className="ml-auto text-[10px] tabular-nums text-zinc-500">
                      {lane.calls_done}/{lane.calls_total}
                    </span>
                  </div>
                  <div className="mt-1 h-1 w-full overflow-hidden rounded-full bg-zinc-200">
                    <div
                      className="h-1 rounded-full bg-gradient-to-r from-emerald-500 to-cyan-500 transition-all duration-700"
                      style={{ width: `${pct}%` }}
                    />
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}

      {/* recent completions + queue count */}
      {(recent.length > 0 || remaining > 0) && (
        <div className="flex flex-wrap items-center gap-1.5 border-t border-zinc-200 px-4 py-2.5 text-[11px] sm:px-5">
          {recent.length > 0 && <span className="mr-1 text-zinc-500">just finished:</span>}
          {recent.map((m) => (
            <span
              key={m}
              title={m}
              className="inline-flex max-w-[10rem] items-center gap-1.5 rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-emerald-700"
            >
              <ProviderLogo provider={m.split('/')[0] ?? ''} size={11} />
              <span className="truncate">{m.split('/')[1] ?? m}</span>
            </span>
          ))}
          {remaining > 0 && (
            <span className="ml-auto rounded-full bg-zinc-100 px-2.5 py-0.5 text-zinc-600">
              {remaining} in queue
            </span>
          )}
        </div>
      )}
    </div>
  );
}

export function LiveLeaderboard({ domain, initialRun, initialEntries, indexVersion }: LiveLeaderboardProps) {
  const [entries, setEntries] = useState<ApiEntry[]>(initialEntries);
  const [run, setRun] = useState<ApiRun | null>(initialRun);
  const [progress, setProgress] = useState<Progress>({ active: false });
  const [fresh, setFresh] = useState<Set<string>>(new Set());
  const knownRef = useRef<Set<string>>(new Set(initialEntries.map((e) => e.model)));

  useEffect(() => {
    let cancelled = false;
    async function tick() {
      try {
        const base = domain ? `/api/v1/leaderboard/${domain}` : '/api/v1/leaderboard';
        const [pRes, lRes] = await Promise.all([
          fetch('/api/v1/benchmark/progress', { cache: 'no-store' }),
          fetch(`${base}?limit=100`, { cache: 'no-store' }),
        ]);
        if (cancelled) return;
        if (pRes.ok) {
          const p = (await pRes.json()) as { progress: Progress };
          setProgress(p.progress ?? { active: false });
        }
        if (lRes.ok) {
          const body = (await lRes.json()) as { run: ApiRun; entries: ApiEntry[] };
          if (body.entries) {
            const newcomers = body.entries
              .map((e) => e.model)
              .filter((slug) => !knownRef.current.has(slug));
            if (newcomers.length > 0) {
              setFresh(new Set(newcomers));
              for (const slug of newcomers) knownRef.current.add(slug);
              setTimeout(() => setFresh(new Set()), 4000);
            }
            setEntries(body.entries);
            setRun(body.run);
          }
        }
      } catch {
        /* transient poll failure — keep last state */
      }
    }
    tick();
    const id = setInterval(tick, POLL_MS);
    return () => {
      cancelled = true;
      clearInterval(id);
    };
  }, [domain]);

  const showSub = Boolean(domain);

  return (
    <div className="space-y-4">
      {progress.active && <ProgressBanner progress={progress} />}
      {run?.kind === 'demo_seed' && <DemoBanner />}

      <div className="flex flex-wrap items-baseline justify-between gap-2">
        <h2 className="text-lg font-semibold text-zinc-900 sm:text-xl">
          {domain ? `${domain.replaceAll('_', ' ')} ranking` : 'Global Index'}
        </h2>
        {run && (
          <span className="text-xs text-zinc-500">
            index v{indexVersion} · run {run.id.slice(0, 8)} ·{' '}
            {new Date(run.created_at).toISOString().slice(0, 16).replace('T', ' ')} UTC
          </span>
        )}
      </div>

      {entries.length === 0 ? (
        <p className="rounded-xl border border-zinc-200 p-6 text-sm text-zinc-600">
          No scores yet{progress.active ? ' — the live benchmark is warming up; first results appear once two models complete.' : '.'}
        </p>
      ) : (
        <>
          {/* Desktop table */}
          <div className="hidden overflow-x-auto md:block">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b border-zinc-200 text-left text-xs uppercase tracking-wide text-zinc-500">
                  <th className="py-2 pr-3">#</th>
                  <th className="py-2 pr-3">Model</th>
                  <th className="py-2 pr-3">Provider</th>
                  <th className="py-2 pr-3 text-right">Score (95% CI)</th>
                  <th className="w-1/4 py-2 pr-3"></th>
                  {showSub && (
                    <>
                      <th className="py-2 pr-3 text-right">Consist.</th>
                      <th className="py-2 pr-3 text-right">Calib.</th>
                      <th className="py-2 pr-3 text-right">Contam. Δ</th>
                      <th className="py-2 pr-3 text-right">p50</th>
                      <th className="py-2 pr-3 text-right">$/1k</th>
                    </>
                  )}
                </tr>
              </thead>
              <tbody>
                {entries.map((e) => (
                  <tr
                    key={e.model}
                    className={
                      'border-b border-zinc-100 transition-colors hover:bg-zinc-50 ' +
                      (fresh.has(e.model) ? 'animate-row-in bg-emerald-50' : '')
                    }
                  >
                    <td className="py-2.5 pr-3 text-zinc-500">{e.rank}</td>
                    <td className="py-2.5 pr-3">
                      <Link
                        href={`/models/${e.model}`}
                        className="flex items-center gap-2.5 font-medium text-zinc-900 hover:text-emerald-600"
                      >
                        <ProviderLogo provider={e.provider} size={18} />
                        {e.name}
                      </Link>
                    </td>
                    <td className="py-2.5 pr-3 text-zinc-600">{e.provider}</td>
                    <td className="py-2.5 pr-3 text-right">
                      <ScoreValue score={e.score} scoreLow={e.score_low} scoreHigh={e.score_high} />
                    </td>
                    <td className="py-2.5 pr-3">
                      <ScoreBar score={e.score} scoreLow={e.score_low} scoreHigh={e.score_high} />
                    </td>
                    {showSub && (
                      <>
                        <td className="py-2.5 pr-3 text-right tabular-nums text-zinc-600">
                          {e.sub_metrics?.consistency?.toFixed(2) ?? '—'}
                        </td>
                        <td className="py-2.5 pr-3 text-right tabular-nums text-zinc-600">
                          {e.sub_metrics?.calibration?.toFixed(2) ?? '—'}
                        </td>
                        <td className="py-2.5 pr-3 text-right tabular-nums text-zinc-600">
                          {e.sub_metrics?.contamination_delta?.toFixed(3) ?? '—'}
                        </td>
                        <td className="py-2.5 pr-3 text-right tabular-nums text-zinc-600">
                          {formatMs(e.sub_metrics?.latency_p50)}
                        </td>
                        <td className="py-2.5 pr-3 text-right tabular-nums text-zinc-600">
                          {formatUsd(e.sub_metrics?.cost_per_1k_items)}
                        </td>
                      </>
                    )}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>

          {/* Mobile cards */}
          <ul className="space-y-2.5 md:hidden">
            {entries.map((e) => (
              <li
                key={e.model}
                className={
                  'rounded-xl border border-zinc-200 bg-white p-3.5 ' +
                  (fresh.has(e.model) ? 'animate-row-in border-emerald-300' : '')
                }
              >
                <div className="flex items-center justify-between gap-3">
                  <div className="flex min-w-0 items-center gap-2.5">
                    <ProviderLogo provider={e.provider} size={22} />
                    <div className="min-w-0">
                      <Link href={`/models/${e.model}`} className="block truncate font-medium text-zinc-900">
                        <span className="mr-2 text-zinc-500">#{e.rank}</span>
                        {e.name}
                      </Link>
                      <span className="text-xs text-zinc-500">{e.provider}</span>
                    </div>
                  </div>
                  <div className="shrink-0 text-right">
                    <ScoreValue score={e.score} scoreLow={e.score_low} scoreHigh={e.score_high} />
                  </div>
                </div>
                <div className="mt-2.5">
                  <ScoreBar score={e.score} scoreLow={e.score_low} scoreHigh={e.score_high} />
                </div>
                {showSub && e.sub_metrics && (
                  <div className="mt-2.5 flex flex-wrap gap-1.5 text-[10px] text-zinc-600">
                    {e.sub_metrics.consistency != null && (
                      <span className="rounded-full bg-zinc-200 px-2 py-0.5">
                        consist {e.sub_metrics.consistency.toFixed(2)}
                      </span>
                    )}
                    {e.sub_metrics.calibration != null && (
                      <span className="rounded-full bg-zinc-200 px-2 py-0.5">
                        calib {e.sub_metrics.calibration.toFixed(2)}
                      </span>
                    )}
                    {e.sub_metrics.contamination_delta != null && (
                      <span className="rounded-full bg-zinc-200 px-2 py-0.5">
                        Δ {e.sub_metrics.contamination_delta.toFixed(3)}
                      </span>
                    )}
                    {e.sub_metrics.latency_p50 != null && (
                      <span className="rounded-full bg-zinc-200 px-2 py-0.5">
                        {formatMs(e.sub_metrics.latency_p50)}
                      </span>
                    )}
                    {e.sub_metrics.cost_per_1k_items != null && (
                      <span className="rounded-full bg-zinc-200 px-2 py-0.5">
                        {formatUsd(e.sub_metrics.cost_per_1k_items)}/1k
                      </span>
                    )}
                  </div>
                )}
              </li>
            ))}
          </ul>
        </>
      )}
    </div>
  );
}
