'use client';

/**
 * PR10.6 ModelRouter Admin Dashboard
 *
 * 三个区：
 *   ① 最近 N 条 RoutingDecision 表（含 matchSource / model / latency / cost / reasoning）
 *   ② Per-org rules 列表（只读 + enable/disable 切换）
 *   ③ 简单聚合统计（按 matchSource / model 计数）
 *
 * 走已有 endpoints：
 *   GET  /api/v1/agent/routing/decisions
 *   （rules CRUD endpoint 暂用 prisma 直查的轻量 GET，写动作下个 PR 接 admin REST）
 */

import { useEffect, useState } from 'react';
import apiClient from '@/lib/api-client';
import { Sparkles, RefreshCw, Loader2, Plus, Trash2 } from 'lucide-react';
import { useTranslation } from '@/hooks/useTranslation';

interface RoutingRuleRow {
  id: string;
  scope: 'ORGANIZATION' | 'USER' | 'PROJECT';
  name: string;
  priority: number;
  enabled: boolean;
  pattern: Record<string, unknown>;
  primary: { provider: string; model: string };
  fallbacks: Array<{ provider: string; model: string }>;
  reasoning: string | null;
}

interface RoutingDecisionRow {
  id: string;
  sessionId: string | null;
  matchSource: 'RULE' | 'LLM_ROUTED' | 'SCOPE_OVERRIDE' | 'DEFAULT';
  matchedRuleId: string | null;
  primaryProvider: string;
  primaryModel: string;
  actualLatencyMs: number | null;
  actualCostUsd: number | null;
  decision: { reasoning?: string };
  request: { taskType?: string; contextTokens?: number };
  createdAt: string;
}

export default function ModelRouterAdminPage() {
  const { t } = useTranslation();
  const tr = t.agent.admin.routing;
  const [decisions, setDecisions] = useState<RoutingDecisionRow[]>([]);
  const [rules, setRules] = useState<RoutingRuleRow[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [showNew, setShowNew] = useState(false);

  const refresh = async () => {
    setLoading(true);
    setError(null);
    try {
      const [decisionsR, rulesR] = await Promise.all([
        apiClient.get('/agent/routing/decisions', { params: { limit: 100 } }) as unknown as Promise<{ items: RoutingDecisionRow[] }>,
        apiClient.get('/agent/admin/rules') as unknown as Promise<{ items: RoutingRuleRow[] }>,
      ]);
      setDecisions(decisionsR.items);
      setRules(rulesR.items);
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
    } finally {
      setLoading(false);
    }
  };

  const toggleRule = async (rule: RoutingRuleRow) => {
    try {
      await apiClient.patch(`/agent/admin/rules/${rule.id}`, { enabled: !rule.enabled });
      await refresh();
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
    }
  };

  const deleteRule = async (rule: RoutingRuleRow) => {
    if (!confirm(tr.deleteConfirm.replace('{name}', rule.name))) return;
    try {
      await apiClient.delete(`/agent/admin/rules/${rule.id}`);
      await refresh();
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
    }
  };

  const createRule = async (form: {
    name: string;
    priority: number;
    pattern: string;
    provider: string;
    model: string;
    scope: 'ORGANIZATION' | 'USER' | 'PROJECT';
    scopeRefId: string;
  }) => {
    let pattern: unknown = {};
    try {
      pattern = JSON.parse(form.pattern || '{}');
    } catch {
      setError('pattern 不是合法 JSON');
      return;
    }
    try {
      await apiClient.post('/agent/admin/rules', {
        name: form.name,
        priority: form.priority,
        scope: form.scope,
        ...(form.scopeRefId.trim() ? { scopeRefId: form.scopeRefId.trim() } : {}),
        pattern,
        primary: { provider: form.provider, model: form.model },
        fallbacks: [],
      });
      setShowNew(false);
      await refresh();
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
    }
  };

  useEffect(() => {
    void refresh();
  }, []);

  const total = decisions.length;
  const bySource = decisions.reduce<Record<string, number>>((acc, d) => {
    acc[d.matchSource] = (acc[d.matchSource] ?? 0) + 1;
    return acc;
  }, {});
  const byModel = decisions.reduce<Record<string, number>>((acc, d) => {
    const k = `${d.primaryProvider}/${d.primaryModel}`;
    acc[k] = (acc[k] ?? 0) + 1;
    return acc;
  }, {});
  const avgLatency = total > 0 ? Math.round(decisions.filter(d => d.actualLatencyMs).reduce((s, d) => s + (d.actualLatencyMs ?? 0), 0) / decisions.filter(d => d.actualLatencyMs).length) : 0;
  const totalCost = decisions.reduce((s, d) => s + (d.actualCostUsd ?? 0), 0);

  return (
    <div className="h-screen w-screen overflow-y-auto bg-neutral-50 px-8 py-6">
      <div className="mx-auto max-w-6xl space-y-6">
        <header className="flex items-center justify-between">
          <div>
            <h1 className="flex items-center gap-2 text-2xl font-bold text-neutral-900">
              <Sparkles className="h-6 w-6 text-blue-600" /> ModelRouter Admin Dashboard
            </h1>
            <p className="mt-1 text-sm text-neutral-500">
              PR10.6 — 路由决策可观测性 + 规则查看（PR3.5 G10 核心）
            </p>
          </div>
          <button
            onClick={refresh}
            className="flex items-center gap-1.5 rounded-md border border-neutral-200 bg-white px-3 py-1.5 text-sm transition hover:bg-neutral-50"
          >
            {loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCw className="h-4 w-4" />}
            刷新
          </button>
        </header>

        {error ? (
          <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">{error}</div>
        ) : null}

        {/* 聚合统计 */}
        <section className="grid grid-cols-1 gap-4 md:grid-cols-4">
          <StatCard label="决策总数" value={String(total)} />
          <StatCard label="平均延迟" value={`${avgLatency} ms`} />
          <StatCard label="累计成本" value={`$${totalCost.toFixed(4)}`} />
          <StatCard label="活跃 model" value={String(Object.keys(byModel).length)} />
        </section>

        {/* 按 matchSource 分布 */}
        <section className="grid grid-cols-1 gap-4 md:grid-cols-2">
          <Panel title="按 matchSource 分布">
            <BarChart data={bySource} colors={{
              RULE: 'bg-blue-500',
              LLM_ROUTED: 'bg-purple-500',
              SCOPE_OVERRIDE: 'bg-amber-500',
              DEFAULT: 'bg-neutral-400',
            }} />
          </Panel>
          <Panel title="按 model 分布">
            <BarChart data={byModel} colors={{}} />
          </Panel>
        </section>

        {/* 规则 CRUD */}
        <Panel title={`路由规则（${rules.length}）`}>
          <div className="mb-2 flex justify-end">
            <button
              onClick={() => setShowNew(!showNew)}
              className="flex items-center gap-1 rounded-md border border-blue-200 bg-blue-50 px-2 py-1 text-xs text-blue-700 hover:bg-blue-100"
            >
              <Plus className="h-3 w-3" /> {tr.newRule}
            </button>
          </div>
          {showNew ? <NewRuleForm tr={tr} onSubmit={createRule} onCancel={() => setShowNew(false)} /> : null}
          <div className="overflow-auto">
            <table className="w-full text-xs">
              <thead className="bg-neutral-100">
                <tr>
                  <th className="px-2 py-1.5 text-left font-medium">{tr.tableHeaders.name}</th>
                  <th className="px-2 py-1.5 text-left font-medium">scope</th>
                  <th className="px-2 py-1.5 text-right font-medium">priority</th>
                  <th className="px-2 py-1.5 text-left font-medium">primary</th>
                  <th className="px-2 py-1.5 text-left font-medium">pattern</th>
                  <th className="px-2 py-1.5 text-center font-medium">enabled</th>
                  <th className="px-2 py-1.5 text-center font-medium">{tr.tableHeaders.actions}</th>
                </tr>
              </thead>
              <tbody>
                {rules.map((r) => (
                  <tr key={r.id} className="border-t border-neutral-200">
                    <td className="px-2 py-1.5">{r.name}</td>
                    <td className="px-2 py-1.5 font-mono text-[10px]">{r.scope}</td>
                    <td className="px-2 py-1.5 text-right tabular-nums">{r.priority}</td>
                    <td className="px-2 py-1.5 font-mono">
                      {r.primary.provider}/{r.primary.model}
                    </td>
                    <td className="px-2 py-1.5 font-mono text-[10px] text-neutral-600">
                      {JSON.stringify(r.pattern).slice(0, 60)}
                    </td>
                    <td className="px-2 py-1.5 text-center">
                      <input
                        type="checkbox"
                        checked={r.enabled}
                        onChange={() => toggleRule(r)}
                        aria-label={`enable rule ${r.name}`}
                      />
                    </td>
                    <td className="px-2 py-1.5 text-center">
                      <button
                        onClick={() => deleteRule(r)}
                        className="text-red-600 hover:text-red-800"
                        aria-label={`delete rule ${r.name}`}
                      >
                        <Trash2 className="h-3.5 w-3.5" />
                      </button>
                    </td>
                  </tr>
                ))}
                {rules.length === 0 ? (
                  <tr>
                    <td colSpan={7} className="py-6 text-center text-sm text-neutral-400">{tr.empty.rules}</td>
                  </tr>
                ) : null}
              </tbody>
            </table>
          </div>
        </Panel>

        {/* 决策历史表 */}
        <Panel title={`最近 ${decisions.length} 条决策`}>
          <div className="max-h-[600px] overflow-auto">
            <table className="w-full text-xs">
              <thead className="sticky top-0 bg-neutral-100">
                <tr>
                  <th className="px-2 py-2 text-left font-medium">时间</th>
                  <th className="px-2 py-2 text-left font-medium">来源</th>
                  <th className="px-2 py-2 text-left font-medium">model</th>
                  <th className="px-2 py-2 text-left font-medium">任务</th>
                  <th className="px-2 py-2 text-left font-medium">tokens</th>
                  <th className="px-2 py-2 text-right font-medium">延迟</th>
                  <th className="px-2 py-2 text-right font-medium">成本</th>
                  <th className="px-2 py-2 text-left font-medium">reasoning</th>
                </tr>
              </thead>
              <tbody>
                {decisions.map((d) => (
                  <tr key={d.id} className="border-t border-neutral-200 hover:bg-neutral-50">
                    <td className="px-2 py-1.5 font-mono text-[10px] text-neutral-600">
                      {new Date(d.createdAt).toLocaleTimeString()}
                    </td>
                    <td className="px-2 py-1.5">
                      <SourceBadge source={d.matchSource} />
                    </td>
                    <td className="px-2 py-1.5 font-mono">
                      {d.primaryProvider}/{d.primaryModel}
                    </td>
                    <td className="px-2 py-1.5">{d.request?.taskType ?? '—'}</td>
                    <td className="px-2 py-1.5 text-right tabular-nums">
                      {d.request?.contextTokens ?? '—'}
                    </td>
                    <td className="px-2 py-1.5 text-right tabular-nums">
                      {d.actualLatencyMs ? `${d.actualLatencyMs}ms` : '—'}
                    </td>
                    <td className="px-2 py-1.5 text-right tabular-nums">
                      {d.actualCostUsd ? `$${d.actualCostUsd.toFixed(4)}` : '—'}
                    </td>
                    <td className="px-2 py-1.5 text-neutral-600">{d.decision?.reasoning ?? '—'}</td>
                  </tr>
                ))}
              </tbody>
            </table>
            {decisions.length === 0 ? (
              <div className="py-8 text-center text-sm text-neutral-400">{tr.empty.decisions}</div>
            ) : null}
          </div>
        </Panel>
      </div>
    </div>
  );
}

function StatCard({ label, value }: { label: string; value: string }) {
  return (
    <div className="rounded-lg border border-neutral-200 bg-white p-4">
      <div className="text-xs text-neutral-500">{label}</div>
      <div className="mt-1 text-2xl font-bold text-neutral-900">{value}</div>
    </div>
  );
}

function Panel({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <div className="rounded-lg border border-neutral-200 bg-white p-4">
      <div className="mb-3 text-sm font-semibold text-neutral-700">{title}</div>
      {children}
    </div>
  );
}

function SourceBadge({ source }: { source: string }) {
  const colors: Record<string, string> = {
    RULE: 'bg-blue-100 text-blue-700',
    LLM_ROUTED: 'bg-purple-100 text-purple-700',
    SCOPE_OVERRIDE: 'bg-amber-100 text-amber-700',
    DEFAULT: 'bg-neutral-100 text-neutral-600',
  };
  return (
    <span className={`rounded px-1.5 py-0.5 text-[10px] font-medium ${colors[source] ?? colors.DEFAULT}`}>
      {source.replace('_', ' ')}
    </span>
  );
}

type TR = ReturnType<typeof useTranslation>['t']['agent']['admin']['routing'];

function NewRuleForm({
  tr,
  onSubmit,
  onCancel,
}: {
  tr: TR;
  onSubmit: (f: {
    name: string;
    priority: number;
    pattern: string;
    provider: string;
    model: string;
    scope: 'ORGANIZATION' | 'USER' | 'PROJECT';
    scopeRefId: string;
  }) => void;
  onCancel: () => void;
}) {
  const [name, setName] = useState('');
  const [priority, setPriority] = useState(500);
  const [pattern, setPattern] = useState('{}');
  const [provider, setProvider] = useState('qwen');
  const [model, setModel] = useState('qwen-plus');
  const [scope, setScope] = useState<'ORGANIZATION' | 'USER' | 'PROJECT'>('ORGANIZATION');
  const [scopeRefId, setScopeRefId] = useState('');
  return (
    <div className="mb-3 rounded-md border border-neutral-200 bg-neutral-50 p-3 text-xs">
      <div className="grid grid-cols-2 gap-2">
        <label className="flex flex-col gap-1">
          <span className="text-neutral-600">{tr.form.name}</span>
          <input
            value={name}
            onChange={(e) => setName(e.target.value)}
            className="rounded border border-neutral-300 px-2 py-1"
            placeholder={tr.form.namePlaceholder}
          />
        </label>
        <label className="flex flex-col gap-1">
          <span className="text-neutral-600">{tr.form.priority}</span>
          <input
            type="number"
            value={priority}
            onChange={(e) => setPriority(Number(e.target.value))}
            className="rounded border border-neutral-300 px-2 py-1"
          />
        </label>
        <label className="flex flex-col gap-1">
          <span className="text-neutral-600">{tr.form.scope}</span>
          <select
            value={scope}
            onChange={(e) => setScope(e.target.value as 'ORGANIZATION' | 'USER' | 'PROJECT')}
            className="rounded border border-neutral-300 px-2 py-1"
          >
            <option value="ORGANIZATION">ORGANIZATION</option>
            <option value="USER">USER</option>
            <option value="PROJECT">PROJECT</option>
          </select>
        </label>
        <label className="flex flex-col gap-1">
          <span className="text-neutral-600">{tr.form.scopeRefId}</span>
          <input
            value={scopeRefId}
            onChange={(e) => setScopeRefId(e.target.value)}
            className="rounded border border-neutral-300 px-2 py-1 font-mono"
            placeholder={scope === 'ORGANIZATION' ? '(auto = current org)' : 'uuid'}
          />
        </label>
        <label className="flex flex-col gap-1">
          <span className="text-neutral-600">{tr.form.provider}</span>
          <input
            value={provider}
            onChange={(e) => setProvider(e.target.value)}
            className="rounded border border-neutral-300 px-2 py-1"
          />
        </label>
        <label className="flex flex-col gap-1">
          <span className="text-neutral-600">{tr.form.model}</span>
          <input
            value={model}
            onChange={(e) => setModel(e.target.value)}
            className="rounded border border-neutral-300 px-2 py-1"
          />
        </label>
      </div>
      <label className="mt-2 flex flex-col gap-1">
        <span className="text-neutral-600">{tr.form.pattern}</span>
        <textarea
          value={pattern}
          onChange={(e) => setPattern(e.target.value)}
          className="h-20 rounded border border-neutral-300 px-2 py-1 font-mono"
          placeholder={tr.form.patternPlaceholder}
        />
      </label>
      <div className="mt-2 flex justify-end gap-2">
        <button
          onClick={onCancel}
          className="rounded border border-neutral-300 px-3 py-1 hover:bg-neutral-100"
        >
          {tr.form.cancel}
        </button>
        <button
          onClick={() => {
            if (!name.trim()) return;
            onSubmit({ name: name.trim(), priority, pattern, provider, model, scope, scopeRefId });
          }}
          className="rounded bg-blue-600 px-3 py-1 text-white hover:bg-blue-700"
        >
          {tr.form.create}
        </button>
      </div>
    </div>
  );
}

function BarChart({ data, colors }: { data: Record<string, number>; colors: Record<string, string> }) {
  const entries = Object.entries(data).sort(([, a], [, b]) => b - a);
  const max = Math.max(...entries.map(([, v]) => v), 1);
  return (
    <div className="space-y-1.5">
      {entries.map(([k, v]) => (
        <div key={k} className="flex items-center gap-2">
          <div className="w-32 truncate text-xs text-neutral-700">{k}</div>
          <div className="flex-1 overflow-hidden rounded bg-neutral-100">
            <div
              className={`h-5 ${colors[k] ?? 'bg-blue-500'} text-right`}
              style={{ width: `${(v / max) * 100}%` }}
            >
              <span className="pr-1.5 text-[10px] leading-5 text-white">{v}</span>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}
