import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
import { toast } from 'sonner';
import * as echarts from 'echarts/core';
import { ScatterChart, BarChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
import { GridComponent, TooltipComponent, LegendComponent, TitleComponent, DataZoomComponent } from 'echarts/components';
import { buildEChartsTheme } from './buildEChartsTheme';
import {
  Play,
  Loader2,
  BarChart3,
  Table,
  Brain,
  Code,
  Trophy,
} from 'lucide-react';

echarts.use([ScatterChart, BarChart, CanvasRenderer, GridComponent, TooltipComponent, LegendComponent, TitleComponent, DataZoomComponent]);

interface EvalsTabProps {
  providerIds: string[];
}

interface EvalSuite {
  id: string;
  name: string;
  kind: string;
  version: number;
  tasks: unknown[];
  judgeModel: string | null;
  createdAt: string;
}

interface EvalRun {
  id: string;
  suiteId: string;
  jobType: string;
  providerId: string;
  model: string;
  quant: string | null;
  status: string;
  judgeModel: string | null;
  startedAt: string | null;
  finishedAt: string | null;
  totalTasks: number;
  completedTasks: number;
  aggregate: Record<string, unknown> | null;
  error: string | null;
  createdAt: string;
}

interface LeaderboardEntry {
  providerId: string;
  model: string;
  quant: string | null;
  suiteKind: string;
  avgScore: number | null;
  runCount: number;
  latestRunAt: string;
}

async function fetchSuites(): Promise<EvalSuite[]> {
  const res = await fetch('/api/control/eval/suites');
  const data = await res.json() as { suites: EvalSuite[] };
  return data.suites ?? [];
}

async function fetchRuns(suiteId?: string): Promise<EvalRun[]> {
  const url = suiteId ? `/api/control/eval/runs?suiteId=${suiteId}` : '/api/control/eval/runs';
  const res = await fetch(url);
  const data = await res.json() as { runs: EvalRun[] };
  return data.runs ?? [];
}

async function fetchLeaderboard(kind?: string): Promise<LeaderboardEntry[]> {
  const url = kind ? `/api/control/eval/leaderboard?kind=${kind}` : '/api/control/eval/leaderboard';
  const res = await fetch(url);
  const data = await res.json() as { leaderboard: LeaderboardEntry[] };
  return data.leaderboard ?? [];
}

async function runEval(suiteId: string, providerId: string, model: string): Promise<void> {
  const res = await fetch('/api/control/eval/run', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ suiteId, providerId, model }),
  });
  if (!res.ok) {
    throw new Error(`eval run failed: ${res.status}`);
  }
}

export function EvalsTab({ providerIds }: EvalsTabProps) {
  const [suites, setSuites] = useState<EvalSuite[]>([]);
  const [runs, setRuns] = useState<EvalRun[]>([]);
  // AUD6: O(1) suite lookup per run row instead of suites.find() in the render map.
  const suiteMap = useMemo(() => new Map(suites.map((s) => [s.id, s])), [suites]);
  // AUD5: controlled launcher inputs (was document.getElementById).
  const [launchSuite, setLaunchSuite] = useState('');
  const [launchProvider, setLaunchProvider] = useState('');
  const [launchModel, setLaunchModel] = useState('');
  const [leaderboard, setLeaderboard] = useState<LeaderboardEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [running, setRunning] = useState<string | null>(null);
  const [activeView, setActiveView] = useState<'leaderboard' | 'runs' | 'scatter'>('leaderboard');
  const [_suiteFilter, _setSuiteFilter] = useState<string>('all');
  const [kindFilter, setKindFilter] = useState<string>('all');
  const scatterRef = useRef<HTMLDivElement>(null);
  const barRef = useRef<HTMLDivElement>(null);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const [suitesData, runsData, lbData] = await Promise.all([
        fetchSuites(),
        fetchRuns(),
        fetchLeaderboard(kindFilter !== 'all' ? kindFilter : undefined),
      ]);
      setSuites(suitesData);
      setRuns(runsData);
      setLeaderboard(lbData);
    } catch (err) {
      console.error('evals: load failed', err);
    } finally {
      setLoading(false);
    }
  }, [kindFilter]);

  useEffect(() => {
    load();
  }, [load]);

  // Scatter chart: speed x quality
  useEffect(() => {
    if (!scatterRef.current || activeView !== 'scatter') return;

    const chart = echarts.init(scatterRef.current, buildEChartsTheme() as echarts.EChartsCoreOption);

    const scatterData = leaderboard.map((entry) => ({
      x: entry.avgScore ?? 0,
      y: entry.runCount,
      name: `${entry.model}${entry.quant ? ` (${entry.quant})` : ''}`,
      providerId: entry.providerId,
      suiteKind: entry.suiteKind,
    }));

    const option: echarts.EChartsCoreOption = {
      backgroundColor: 'transparent',
      title: {
        text: 'Quality vs Run Frequency',
        left: 'center',
        textStyle: { color: 'var(--foreground)', fontSize: 14 },
      },
      tooltip: {
        trigger: 'item',
        formatter: (p: { data: { name: string; providerId: string; x: number; y: number } }) => {
          const d = p.data as { name: string; providerId: string; x: number; y: number };
          return `<b>${d.name}</b><br/>Provider: ${d.providerId}<br/>Avg Score: ${d.x.toFixed(2)}<br/>Runs: ${d.y}`;
        },
      },
      legend: {
        data: [...new Set(leaderboard.map((e) => e.providerId))],
        textStyle: { color: 'var(--foreground)' },
        top: 30,
      },
      grid: { left: 60, right: 30, top: 70, bottom: 50 },
      xAxis: {
        name: 'Avg Score',
        nameTextStyle: { color: 'var(--foreground)' },
        axisLabel: { color: 'var(--foreground)' },
        splitLine: { lineStyle: { color: 'var(--border, #333)' } },
      },
      yAxis: {
        name: 'Run Count',
        nameTextStyle: { color: 'var(--foreground)' },
        axisLabel: { color: 'var(--foreground)' },
        splitLine: { lineStyle: { color: 'var(--border, #333)' } },
      },
      series: [...new Set(leaderboard.map((e) => e.providerId))].map((pid, i) => ({
        type: 'scatter',
        name: pid,
        data: scatterData.filter((d) => d.providerId === pid).map((d) => [d.x, d.y, d.name]),
        symbolSize: (val: number[]) => Math.max(8, (val[1] ?? 1) * 3),
        itemStyle: {
          color: ['#60a5fa', '#f472b6', '#34d399', '#fbbf24'][i % 4],
        },
      })),
    };

    chart.setOption(option);

    const handleResize = () => chart.resize();
    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
      chart.dispose();
    };
  }, [leaderboard, activeView]);

  // Bar chart for leaderboard view
  useEffect(() => {
    if (!barRef.current || activeView !== 'leaderboard') return;

    const chart = echarts.init(barRef.current, buildEChartsTheme() as echarts.EChartsCoreOption);

    const sorted = [...leaderboard].sort((a, b) => (b.avgScore ?? 0) - (a.avgScore ?? 0)).slice(0, 20);

    const option: echarts.EChartsCoreOption = {
      backgroundColor: 'transparent',
      title: {
        text: 'Model Leaderboard',
        left: 'center',
        textStyle: { color: 'var(--foreground)', fontSize: 14 },
      },
      tooltip: {
        trigger: 'axis',
        axisPointer: { type: 'shadow' },
        formatter: (params: unknown[]) => {
          const p = params[0] as { name: string; value: number };
          return `<b>${p.name}</b><br/>Score: ${(p.value as number).toFixed(2)}`;
        },
      },
      grid: { left: 120, right: 30, top: 60, bottom: 30 },
      xAxis: {
        type: 'value',
        axisLabel: { color: 'var(--foreground)' },
        splitLine: { lineStyle: { color: 'var(--border, #333)' } },
      },
      yAxis: {
        type: 'category',
        data: sorted.map((e) => e.model).reverse(),
        axisLabel: { color: 'var(--foreground)', fontSize: 11 },
        axisLine: { lineStyle: { color: 'var(--border, #333)' } },
      },
      series: [{
        type: 'bar',
        data: sorted.map((e) => e.avgScore ?? 0).reverse(),
        itemStyle: {
          color: (params: { dataIndex?: number }) => {
            const idx = params.dataIndex ?? 0;
            const score = sorted[sorted.length - 1 - idx]?.avgScore ?? 0;
            if (score != null && score >= 0.8) return '#34d399';
            if (score != null && score >= 0.5) return '#60a5fa';
            return '#f87171';
          },
        },
      }],
    };

    chart.setOption(option);

    const handleResize = () => chart.resize();
    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
      chart.dispose();
    };
  }, [leaderboard, activeView]);

  const handleRunEval = async (suiteId: string, providerId: string, model: string) => {
    const key = `${suiteId}-${providerId}-${model}`;
    setRunning(key);
    try {
      await runEval(suiteId, providerId, model);
      toast.success(`Eval queued — watch the Jobs tab`);
    } catch (err) {
      // C2: surface the failure instead of swallowing it to the console.
      toast.error(err instanceof Error ? err.message : 'eval run failed');
    } finally {
      setRunning(null);
    }
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center flex-1">
        <Loader2 className="size-5 animate-spin text-muted-foreground" />
      </div>
    );
  }

  return (
    <div className="flex-1 flex flex-col min-h-0">
      {/* View tabs */}
      <div className="flex items-center gap-2 px-4 py-2 border-b border-border/40">
        <button
          onClick={() => setActiveView('leaderboard')}
          className={`px-3 py-1.5 text-xs rounded-md transition-colors ${activeView === 'leaderboard' ? 'bg-primary/10 text-primary' : 'text-muted-foreground hover:text-foreground'}`}
        >
          <Trophy className="size-3 inline mr-1" />
          Leaderboard
        </button>
        <button
          onClick={() => setActiveView('scatter')}
          className={`px-3 py-1.5 text-xs rounded-md transition-colors ${activeView === 'scatter' ? 'bg-primary/10 text-primary' : 'text-muted-foreground hover:text-foreground'}`}
        >
          <BarChart3 className="size-3 inline mr-1" />
          Scatter
        </button>
        <button
          onClick={() => setActiveView('runs')}
          className={`px-3 py-1.5 text-xs rounded-md transition-colors ${activeView === 'runs' ? 'bg-primary/10 text-primary' : 'text-muted-foreground hover:text-foreground'}`}
        >
          <Table className="size-3 inline mr-1" />
          Runs
        </button>

        <div className="flex-1" />

        <select
          value={kindFilter}
          onChange={(e) => setKindFilter(e.target.value)}
          className="text-xs bg-background border border-border rounded-md px-2 py-1"
        >
          <option value="all">All Kinds</option>
          <option value="chat">Chat</option>
          <option value="code">Code</option>
        </select>
      </div>

      {/* Content */}
      <div className="flex-1 overflow-auto">
        {activeView === 'leaderboard' && (
          <div className="p-4">
            <div ref={barRef} style={{ width: '100%', height: '400px' }} />
            <div className="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
              {leaderboard.map((entry) => (
                <div key={`${entry.providerId}-${entry.model}-${entry.suiteKind}`} className="border border-border/40 rounded-lg p-3 bg-card/50">
                  <div className="flex items-center justify-between">
                    <span className="text-sm font-medium">{entry.model}</span>
                    <span className="text-xs text-muted-foreground">{entry.providerId}</span>
                  </div>
                  <div className="flex items-center gap-2 mt-1">
                    {entry.suiteKind === 'code' ? (
                      <Code className="size-3 text-blue-400" />
                    ) : (
                      <Brain className="size-3 text-purple-400" />
                    )}
                    <span className="text-xs text-muted-foreground capitalize">{entry.suiteKind}</span>
                    {entry.quant && <span className="text-xs text-muted-foreground">{entry.quant}</span>}
                  </div>
                  <div className="mt-2 flex items-center justify-between">
                    <span className="text-lg font-mono">{entry.avgScore?.toFixed(2) ?? 'N/A'}</span>
                    <span className="text-xs text-muted-foreground">{entry.runCount} runs</span>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {activeView === 'scatter' && (
          <div className="p-4">
            <div ref={scatterRef} style={{ width: '100%', height: '500px' }} />
          </div>
        )}

        {activeView === 'runs' && (
          <div className="p-4">
            {/* Run launcher */}
            <div className="mb-4 p-3 border border-border/40 rounded-lg bg-card/30">
              <h3 className="text-sm font-medium mb-2">Launch Eval</h3>
              <div className="flex flex-wrap gap-2">
                <select
                  value={launchSuite || (suites[0]?.id ?? '')}
                  onChange={(e) => setLaunchSuite(e.target.value)}
                  className="text-xs bg-background border border-border rounded-md px-2 py-1"
                >
                  {suites.map((s) => (
                    <option key={s.id} value={s.id}>{s.name} ({s.kind})</option>
                  ))}
                </select>
                <select
                  value={launchProvider || (providerIds[0] ?? '')}
                  onChange={(e) => setLaunchProvider(e.target.value)}
                  className="text-xs bg-background border border-border rounded-md px-2 py-1"
                >
                  {providerIds.map((pid) => (
                    <option key={pid} value={pid}>{pid}</option>
                  ))}
                </select>
                <input
                  value={launchModel}
                  onChange={(e) => setLaunchModel(e.target.value)}
                  placeholder="Model ID"
                  className="text-xs bg-background border border-border rounded-md px-2 py-1 flex-1 min-w-[120px]"
                />
                <button
                  disabled={running !== null}
                  onClick={async () => {
                    const suiteId = launchSuite || suites[0]?.id || '';
                    const providerId = launchProvider || providerIds[0] || '';
                    const model = launchModel.trim();
                    if (!suiteId || !providerId || !model) {
                      toast.error('Pick a suite, provider, and model first');
                      return;
                    }
                    await handleRunEval(suiteId, providerId, model);
                  }}
                  className="flex items-center gap-1 px-3 py-1 text-xs bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50"
                >
                  {running !== null ? <Loader2 className="size-3 animate-spin" /> : <Play className="size-3" />}
                  Run
                </button>
              </div>
            </div>

            {/* Runs table */}
            <div className="overflow-x-auto">
              <table className="w-full text-xs">
                <thead>
                  <tr className="border-b border-border/40 text-muted-foreground">
                    <th className="text-left py-2 px-3">Run ID</th>
                    <th className="text-left py-2 px-3">Suite</th>
                    <th className="text-left py-2 px-3">Provider</th>
                    <th className="text-left py-2 px-3">Model</th>
                    <th className="text-left py-2 px-3">Status</th>
                    <th className="text-left py-2 px-3">Score</th>
                    <th className="text-left py-2 px-3">Progress</th>
                    <th className="text-left py-2 px-3">Started</th>
                  </tr>
                </thead>
                <tbody>
                  {runs.map((run) => {
                    const suite = suiteMap.get(run.suiteId);
                    return (
                      <tr key={run.id} className="border-b border-border/20 hover:bg-muted/20">
                        <td className="py-2 px-3 font-mono">{run.id.slice(0, 16)}</td>
                        <td className="py-2 px-3">{suite?.name ?? run.suiteId}</td>
                        <td className="py-2 px-3">{run.providerId}</td>
                        <td className="py-2 px-3">{run.model}</td>
                        <td className="py-2 px-3">
                          <span className={`px-2 py-0.5 rounded-full text-xs ${
                            run.status === 'completed' ? 'bg-green-500/20 text-green-400' :
                            run.status === 'running' ? 'bg-blue-500/20 text-blue-400' :
                            run.status === 'failed' ? 'bg-red-500/20 text-red-400' :
                            'bg-yellow-500/20 text-yellow-400'
                          }`}>
                            {run.status}
                          </span>
                        </td>
                        <td className="py-2 px-3 font-mono">
                          {run.aggregate?.avgScore != null ? (run.aggregate.avgScore as number).toFixed(2) : '-'}
                        </td>
                        <td className="py-2 px-3">
                          {run.totalTasks > 0 ? `${run.completedTasks}/${run.totalTasks}` : '-'}
                        </td>
                        <td className="py-2 px-3 text-muted-foreground">
                          {run.startedAt ? new Date(run.startedAt).toLocaleTimeString() : '-'}
                        </td>
                      </tr>
                    );
                  })}
                  {runs.length === 0 && (
                    <tr>
                      <td colSpan={8} className="py-8 text-center text-muted-foreground">
                        No eval runs yet. Launch one above.
                      </td>
                    </tr>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
