/**
 * llmindex.io — interactive live Pareto frontier chart (full-page, SVG)
 * Author:  Simon-Pierre Boucher
 * Contact: contact@spboucher.ai
 * License: Proprietary — © Simon-Pierre Boucher, all rights reserved
 *
 * Form: scatter + Pareto step line (quality vs log-cost). Color encodes the
 * two-class identity frontier/dominated — palette #047857/#7c3aed validated
 * (lightness band, chroma, CVD ΔE 23.9 deutan, normal-vision ΔE 32, contrast).
 * Provider identity rides on labels/tooltips/logos, never on hue cycling.
 * CI whiskers on every point; frontier points carry direct labels; per-mark
 * hover tooltips with enlarged hit targets; polls fresh data every 15 s and
 * animates newly landed models in.
 */
'use client';

import { useEffect, useMemo, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import { ProviderLogo } from './ProviderLogo';

export interface FrontierPoint {
  model: string;
  name: string;
  provider: string;
  score: number;
  score_low: number;
  score_high: number;
  latency_p50: number | null;
  cost_per_1k_items: number;
  on_frontier: boolean;
}

const FRONTIER = '#047857';
const DOMINATED = '#7c3aed';
const INK = '#3f3f46';
const INK_MUTED = '#a1a1aa';
const GRID = '#e4e4e7';
const POLL_MS = 15000;

const W = 1280;
const H = 720;
const M = { top: 28, right: 48, bottom: 64, left: 72 };
const IW = W - M.left - M.right;
const IH = H - M.top - M.bottom;

function fmtCost(v: number): string {
  if (v >= 100) return `$${Math.round(v)}`;
  if (v >= 1) return `$${v.toFixed(v >= 10 ? 0 : 1)}`;
  if (v >= 0.01) return `$${v.toFixed(2)}`;
  return `$${v.toFixed(3)}`;
}

export function FrontierChart({ initial }: { initial: FrontierPoint[] }) {
  const router = useRouter();
  const [points, setPoints] = useState<FrontierPoint[]>(initial);
  const [hover, setHover] = useState<FrontierPoint | null>(null);
  const [fresh, setFresh] = useState<Set<string>>(new Set());
  const [updatedAt, setUpdatedAt] = useState<Date | null>(null);
  const knownRef = useRef<Set<string>>(new Set(initial.map((p) => p.model)));

  useEffect(() => {
    let cancelled = false;
    async function tick() {
      try {
        const res = await fetch('/api/v1/efficiency', { cache: 'no-store' });
        if (!res.ok || cancelled) return;
        const body = (await res.json()) as { points: FrontierPoint[] };
        if (!body.points) return;
        const newcomers = body.points.map((p) => p.model).filter((m) => !knownRef.current.has(m));
        if (newcomers.length > 0) {
          setFresh(new Set(newcomers));
          newcomers.forEach((m) => knownRef.current.add(m));
          setTimeout(() => setFresh(new Set()), 5000);
        }
        setPoints(body.points);
        setUpdatedAt(new Date());
      } catch {
        /* keep last state */
      }
    }
    const id = setInterval(tick, POLL_MS);
    tick();
    return () => {
      cancelled = true;
      clearInterval(id);
    };
  }, []);

  const view = useMemo(() => {
    if (points.length === 0) return null;
    const costs = points.map((p) => p.cost_per_1k_items).filter((c) => c > 0);
    const minC = Math.min(...costs);
    const maxC = Math.max(...costs);
    const lo = Math.floor(Math.log10(minC) - 0.15);
    const hi = Math.ceil(Math.log10(maxC) + 0.15);
    const yMin = Math.max(0, Math.floor((Math.min(...points.map((p) => p.score_low)) - 50) / 100) * 100);
    const yMax = Math.min(1000, Math.ceil((Math.max(...points.map((p) => p.score_high)) + 50) / 100) * 100);

    const x = (c: number): number => M.left + ((Math.log10(c) - lo) / (hi - lo)) * IW;
    const y = (s: number): number => M.top + (1 - (s - yMin) / (yMax - yMin)) * IH;

    const xTicks: Array<{ v: number; major: boolean }> = [];
    for (let d = lo; d <= hi; d++) {
      xTicks.push({ v: 10 ** d, major: true });
      for (const m of [2, 5]) {
        const v = m * 10 ** d;
        if (Math.log10(v) < hi) xTicks.push({ v, major: false });
      }
    }
    const yTicks: number[] = [];
    for (let s = yMin; s <= yMax; s += 100) yTicks.push(s);

    // Pareto step polyline (const-right steps in cost order).
    const front = points.filter((p) => p.on_frontier).sort((a, b) => a.cost_per_1k_items - b.cost_per_1k_items);
    let path = '';
    front.forEach((p, i) => {
      const px = x(p.cost_per_1k_items);
      const py = y(p.score);
      if (i === 0) path += `M ${px} ${py}`;
      else path += ` L ${px} ${y(front[i - 1]!.score)} L ${px} ${py}`;
    });
    if (front.length > 0) {
      path += ` L ${M.left + IW} ${y(front[front.length - 1]!.score)}`;
    }

    // Direct labels on frontier points, nudged apart vertically when close.
    const labels = front.map((p) => ({ p, lx: x(p.cost_per_1k_items) + 12, ly: y(p.score) - 10 }));
    for (let i = 1; i < labels.length; i++) {
      const prev = labels[i - 1]!;
      const cur = labels[i]!;
      if (Math.abs(cur.ly - prev.ly) < 16 && cur.lx - prev.lx < 130) cur.ly = prev.ly - 16;
    }

    return { x, y, xTicks, yTicks, path, labels, yMin, yMax };
  }, [points]);

  if (!view || points.length === 0) {
    return (
      <div className="flex h-[50vh] items-center justify-center rounded-2xl border border-zinc-200 bg-white text-sm text-zinc-500">
        Waiting for the first scored models — the chart populates automatically as the live
        benchmark lands them.
      </div>
    );
  }

  const shortName = (slug: string): string => slug.split('/')[1] ?? slug;

  return (
    <div className="space-y-3">
      {/* legend + live status — one row above the chart */}
      <div className="flex flex-wrap items-center gap-x-5 gap-y-2 text-sm">
        <span className="flex items-center gap-2">
          <span className="inline-block h-3 w-3 rounded-full" style={{ background: FRONTIER }} />
          <span className="text-zinc-700">Pareto frontier ({points.filter((p) => p.on_frontier).length})</span>
        </span>
        <span className="flex items-center gap-2">
          <span className="inline-block h-3 w-3 rounded-full" style={{ background: DOMINATED, opacity: 0.75 }} />
          <span className="text-zinc-700">dominated ({points.filter((p) => !p.on_frontier).length})</span>
        </span>
        <span className="flex items-center gap-2 text-zinc-500">
          <span className="inline-block h-3 w-[2px] bg-zinc-400" /> 95% CI
        </span>
        <span className="ml-auto flex items-center gap-2 text-xs text-zinc-500">
          <span className="relative flex h-2 w-2">
            <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 w-2 rounded-full bg-emerald-400" />
          </span>
          live · {points.length} models{updatedAt ? ` · updated ${updatedAt.toLocaleTimeString()}` : ''}
        </span>
      </div>

      <div className="relative overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-sm">
        <svg viewBox={`0 0 ${W} ${H}`} className="block w-full" role="img"
          aria-label="Pareto efficiency frontier: Global Index versus cost per thousand items">
          {/* grid */}
          {view.yTicks.map((s) => (
            <line key={`gy${s}`} x1={M.left} x2={M.left + IW} y1={view.y(s)} y2={view.y(s)}
              stroke={GRID} strokeWidth={1} />
          ))}
          {view.xTicks.filter((t) => t.major).map((t) => (
            <line key={`gx${t.v}`} x1={view.x(t.v)} x2={view.x(t.v)} y1={M.top} y2={M.top + IH}
              stroke={GRID} strokeWidth={1} />
          ))}

          {/* axes labels */}
          {view.yTicks.map((s) => (
            <text key={`ty${s}`} x={M.left - 10} y={view.y(s) + 4} textAnchor="end"
              fontSize={13} fill={INK_MUTED}>{s}</text>
          ))}
          {view.xTicks.map((t) => (
            <text key={`tx${t.v}`} x={view.x(t.v)} y={M.top + IH + (t.major ? 24 : 20)} textAnchor="middle"
              fontSize={t.major ? 13 : 10.5} fill={t.major ? INK_MUTED : '#c4c4cc'}>
              {fmtCost(t.v)}
            </text>
          ))}
          <text x={M.left + IW / 2} y={H - 14} textAnchor="middle" fontSize={14} fill={INK}>
            cost per 1,000 items (USD, log scale) →
          </text>
          <text x={20} y={M.top + IH / 2} textAnchor="middle" fontSize={14} fill={INK}
            transform={`rotate(-90 20 ${M.top + IH / 2})`}>
            Global Index →
          </text>

          {/* frontier step line */}
          <path d={view.path} fill="none" stroke={FRONTIER} strokeWidth={2} strokeLinejoin="round" opacity={0.85} />

          {/* CI whiskers */}
          {points.map((p) => {
            const px = view.x(p.cost_per_1k_items);
            const color = p.on_frontier ? FRONTIER : DOMINATED;
            return (
              <g key={`w${p.model}`} opacity={0.45}>
                <line x1={px} x2={px} y1={view.y(p.score_low)} y2={view.y(p.score_high)}
                  stroke={color} strokeWidth={1.5} />
                <line x1={px - 4} x2={px + 4} y1={view.y(p.score_low)} y2={view.y(p.score_low)} stroke={color} strokeWidth={1.5} />
                <line x1={px - 4} x2={px + 4} y1={view.y(p.score_high)} y2={view.y(p.score_high)} stroke={color} strokeWidth={1.5} />
              </g>
            );
          })}

          {/* dots (2px surface ring separates overlapping marks) */}
          {points.map((p) => (
            <circle key={`d${p.model}`} cx={view.x(p.cost_per_1k_items)} cy={view.y(p.score)}
              r={p.on_frontier ? 7 : 5.5}
              fill={p.on_frontier ? FRONTIER : DOMINATED}
              fillOpacity={p.on_frontier ? 1 : 0.75}
              stroke="#ffffff" strokeWidth={2}
              className={fresh.has(p.model) ? 'animate-row-in' : undefined} />
          ))}

          {/* selective direct labels: frontier only */}
          {view.labels.map(({ p, lx, ly }) => (
            <text key={`l${p.model}`} x={lx} y={ly} fontSize={12.5} fontWeight={600} fill={INK}>
              {shortName(p.model)}
            </text>
          ))}

          {/* enlarged invisible hit targets */}
          {points.map((p) => (
            <circle key={`h${p.model}`} cx={view.x(p.cost_per_1k_items)} cy={view.y(p.score)} r={16}
              fill="transparent" style={{ cursor: 'pointer' }}
              onMouseEnter={() => setHover(p)} onMouseLeave={() => setHover(null)}
              onClick={() => router.push(`/models/${p.model}`)} />
          ))}

          {/* hover ring */}
          {hover && (
            <circle cx={view.x(hover.cost_per_1k_items)} cy={view.y(hover.score)} r={11}
              fill="none" stroke={hover.on_frontier ? FRONTIER : DOMINATED} strokeWidth={2} opacity={0.6} />
          )}
        </svg>

        {/* tooltip */}
        {hover && (
          <div
            className="pointer-events-none absolute z-10 w-64 rounded-xl border border-zinc-200 bg-white p-3 shadow-lg"
            style={{
              left: `min(max(${((view.x(hover.cost_per_1k_items) / W) * 100).toFixed(2)}% - 8rem, 0.5rem), calc(100% - 16.5rem))`,
              top: `calc(${((view.y(hover.score) / H) * 100).toFixed(2)}% - 0.5rem)`,
              transform: 'translateY(-100%)',
            }}
          >
            <div className="flex items-center gap-2">
              <ProviderLogo provider={hover.provider} size={18} />
              <span className="truncate text-sm font-semibold text-zinc-900">{hover.name}</span>
            </div>
            <div className="mt-2 grid grid-cols-2 gap-x-3 gap-y-1 text-xs text-zinc-600">
              <span>Global Index</span>
              <span className="text-right font-semibold tabular-nums text-zinc-900">
                {hover.score} <span className="font-normal text-zinc-500">[{hover.score_low}–{hover.score_high}]</span>
              </span>
              <span>Cost / 1k items</span>
              <span className="text-right tabular-nums">{fmtCost(hover.cost_per_1k_items)}</span>
              <span>Latency p50</span>
              <span className="text-right tabular-nums">
                {hover.latency_p50 != null ? `${(hover.latency_p50 / 1000).toFixed(1)}s` : '—'}
              </span>
              <span>Status</span>
              <span className="text-right">
                {hover.on_frontier ? (
                  <span className="rounded-full bg-emerald-100 px-2 py-0.5 text-emerald-700">frontier</span>
                ) : (
                  <span className="rounded-full bg-violet-100 px-2 py-0.5 text-violet-700">dominated</span>
                )}
              </span>
            </div>
            <p className="mt-2 text-[10px] text-zinc-400">click to open the model page</p>
          </div>
        )}
      </div>
    </div>
  );
}
