import { useEffect, useMemo, useState, type ReactNode } from "react";
import { adminOverview, getStatus, type AdminOverview, type SystemStatus } from "../api";

// 管理端「概览」= 系统控制塔：统筹全系统的吞吐 / 配置态 / 健康，而非某个账号的个人工作台。
// 数据来自 /api/v1/admin/overview（系统级聚合）+ /api/v1/admin/status（实时探活）。

const STATUS_STYLE: Record<string, { label: string; color: string }> = {
  done: { label: "完成", color: "#10b981" },
  running: { label: "运行中", color: "#06b6d4" },
  failed: { label: "失败", color: "#f43f5e" },
  timeout: { label: "超时", color: "#f59e0b" },
  rejected: { label: "已拒绝", color: "#a78bfa" },
  waiting: { label: "待审批", color: "#eab308" },
};
const statusStyle = (s: string) => STATUS_STYLE[s] ?? { label: s, color: "#94a3b8" };

// 模型熔断态 → 展示样式。
const BREAKER_STYLE: Record<string, { label: string; dot: string; text: string }> = {
  closed: { label: "在线", dot: "bg-emerald-500", text: "text-emerald-600" },
  open: { label: "熔断中", dot: "bg-rose-500", text: "text-rose-500" },
  "half-open": { label: "半开探测", dot: "bg-amber-500", text: "text-amber-600" },
  single: { label: "单点", dot: "bg-gray-300", text: "text-gray-400" },
};
const breakerStyle = (s: string) => BREAKER_STYLE[s] ?? { label: s, dot: "bg-gray-300", text: "text-gray-400" };

function last7DaysTrend(trend: { key: string; count: number }[]): { key: string; count: number }[] {
  const byKey = new Map(trend.map((d) => [d.key, d.count]));
  const out: { key: string; count: number }[] = [];
  const now = new Date();
  for (let i = 6; i >= 0; i--) {
    const d = new Date(now);
    d.setDate(now.getDate() - i);
    const key = `${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
    out.push({ key, count: byKey.get(key) ?? 0 });
  }
  return out;
}

export function DashboardPage() {
  const [ov, setOv] = useState<AdminOverview | null>(null);
  const [status, setStatus] = useState<SystemStatus | null>(null);
  const [loading, setLoading] = useState(true);
  const [refreshing, setRefreshing] = useState(false);
  const [updatedAt, setUpdatedAt] = useState<Date | null>(null);
  const [err, setErr] = useState("");

  const load = async () => {
    setRefreshing(true);
    try {
      const [o, s] = await Promise.all([adminOverview(), getStatus()]);
      setOv(o);
      setStatus(s);
      setUpdatedAt(new Date());
      setErr("");
    } catch (er) {
      setErr((er as Error).message);
    } finally {
      setLoading(false);
      setRefreshing(false);
    }
  };

  useEffect(() => {
    void load();
    const t = setInterval(() => void load(), 30000);
    return () => clearInterval(t);
  }, []);

  const trend = useMemo(() => (ov ? last7DaysTrend(ov.task_trend) : []), [ov]);

  if (loading) return <div className="text-sm text-gray-400">加载系统概览中…</div>;
  if (err) return <div className="text-sm text-rose-500">概览加载失败：{err}</div>;
  if (!ov || !status) return null;

  const maxTrend = Math.max(1, ...trend.map((d) => d.count));
  const W = 560;
  const H = 120;
  const pad = 20;
  const pts = trend.map((d, i) => ({
    x: pad + (i * (W - pad * 2)) / Math.max(1, trend.length - 1),
    y: H - pad - (d.count * (H - pad * 2)) / maxTrend,
  }));
  const dPath = pts.reduce((p, pt, i) => p + `${i === 0 ? "M" : "L"} ${pt.x.toFixed(1)} ${pt.y.toFixed(1)} `, "");
  const areaPath = pts.length ? dPath + `L ${pts[pts.length - 1].x} ${H - pad} L ${pts[0].x} ${H - pad} Z` : "";

  const totalStatus = ov.status_count.reduce((s, d) => s + d.count, 0) || 1;
  const upSvc = status.services.filter((s) => s.up).length;
  const svcTotal = status.services.length;
  const goTools = status.tools.find((t) => t.server === "mcp-go")?.tools?.length ?? 0;
  const pyTools = status.tools.find((t) => t.server === "mcp-py")?.tools?.length ?? 0;
  const infraDown = status.infra.filter((i) => !i.up).length;
  const m = ov.models;

  return (
    <div className="space-y-6">
      {/* 顶栏：更新时间 + 刷新 */}
      <div className="flex items-center justify-end gap-3 text-xs text-gray-400">
        {updatedAt && <span>数据更新于 {updatedAt.toLocaleTimeString("zh-CN", { hour12: false })} · 每 30s 自动刷新 · 全平台口径</span>}
        <button
          onClick={() => void load()}
          disabled={refreshing}
          className="flex items-center gap-1 rounded border border-gray-200 px-2.5 py-1 text-gray-500 hover:bg-gray-50 disabled:opacity-40"
        >
          <svg viewBox="0 0 24 24" className={`h-3.5 w-3.5 ${refreshing ? "animate-spin" : ""}`} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M23 4v6h-6 M1 20v-6h6 M3.51 9a9 9 0 0 1 14.85-3.36L23 10 M1 14l4.64 4.36A9 9 0 0 0 20.49 15" />
          </svg>
          {refreshing ? "刷新中" : "刷新"}
        </button>
      </div>

      {/* A. 平台总览（全局口径） */}
      <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
        <MetricCard
          label="平台任务总量"
          icon="tasks"
          tone="violet"
          value={ov.tasks_total.toLocaleString()}
          sub={<span className="text-emerald-600">今日 +{ov.tasks_today}（全系统）</span>}
        />
        <MetricCard
          label="全局评测质量"
          icon="award"
          tone="emerald"
          value={
            <>
              {ov.eval_avg.toFixed(2)} <span className="text-xs font-normal text-gray-400">/ 1.0</span>
            </>
          }
          sub={<span className="text-gray-400">{ov.eval_count} 条评测 · 全平台均值</span>}
        />
        <MetricCard
          label="平台规模"
          icon="users"
          tone="cyan"
          value={ov.users.toLocaleString()}
          sub={<span className="text-gray-400">用户 · {ov.kb_count} 库 / {ov.kb_docs} 文档</span>}
        />
        <MetricCard
          label="服务在线"
          icon="pulse"
          tone={upSvc === svcTotal && infraDown === 0 ? "emerald" : "rose"}
          value={`${upSvc} / ${svcTotal}`}
          sub={
            infraDown === 0 && upSvc === svcTotal ? (
              <span className="text-emerald-600">基建 + 应用全绿 · {goTools + pyTools} 工具</span>
            ) : (
              <span className="text-rose-600">{infraDown > 0 ? `${infraDown} 项基建异常` : "有服务离线"}</span>
            )
          }
        />
      </div>

      {/* B. 控制面配置态（管理端独有） */}
      <div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
        <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
          <div className="mb-3 flex items-center justify-between">
            <h4 className="text-sm font-semibold text-gray-700">模型路由 & Fallback</h4>
            <span className="rounded bg-violet-50 px-2 py-0.5 text-[10px] font-medium text-violet-700">控制面</span>
          </div>
          <div className="space-y-3">
            <Row label="主对话模型">
              {m.active_chat ? (
                <span className="flex items-center gap-1.5">
                  <span className="h-1.5 w-1.5 rounded-full bg-emerald-500" />
                  <code className="text-[11px] text-gray-700">{m.active_chat}</code>
                </span>
              ) : (
                <span className="text-rose-500">未配置</span>
              )}
            </Row>
            <Row label="备用链（failover）">
              {m.fallbacks === 0 ? <span className="text-amber-600">无备用（单点）</span> : <span className="text-gray-500">{m.fallbacks} 个备用模型</span>}
            </Row>
            <Row label="向量模型">
              {m.active_embedding ? <code className="text-[11px] text-gray-700">{m.active_embedding}</code> : <span className="text-rose-500">未配置</span>}
            </Row>
            <Row label="已登记模型">
              <span className="text-gray-500">chat {m.chat_count} · embedding {m.embedding_count}</span>
            </Row>
          </div>

          {/* 运行时 failover/熔断态（来自 dispatcher） */}
          {m.health && m.health.length > 0 && (
            <div className="mt-3 border-t border-gray-50 pt-3">
              <div className="mb-2 text-[10px] font-semibold uppercase tracking-wider text-gray-300">运行时链路态（实时）</div>
              <div className="space-y-1.5">
                {m.health.map((h, i) => {
                  const st = breakerStyle(h.state);
                  return (
                    <div key={`${h.model}-${i}`} className="flex items-center gap-2 text-xs">
                      <span className={`h-2 w-2 shrink-0 rounded-full ${st.dot}`} title={st.label} />
                      <span className="rounded bg-gray-50 px-1.5 text-[10px] text-gray-400">{h.role === "primary" ? "主" : "备"}</span>
                      <code className="min-w-0 flex-1 truncate text-[11px] text-gray-600">{h.model}</code>
                      <span className={`shrink-0 text-[10px] ${st.text}`}>{st.label}</span>
                      {h.fails > 0 && h.state !== "closed" && <span className="shrink-0 text-[10px] text-gray-300">失败 {h.fails}</span>}
                    </div>
                  );
                })}
              </div>
            </div>
          )}
        </div>

        <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
          <div className="mb-3 flex items-center justify-between">
            <h4 className="text-sm font-semibold text-gray-700">提示词控制面</h4>
            <span className="rounded bg-violet-50 px-2 py-0.5 text-[10px] font-medium text-violet-700">控制面</span>
          </div>
          <div className="flex items-baseline gap-6">
            <div>
              <div className="text-2xl font-bold text-gray-800">{ov.prompts.managed}</div>
              <div className="text-[11px] text-gray-400">受管提示词</div>
            </div>
            <div>
              <div className="text-2xl font-bold text-violet-600">{ov.prompts.overrides}</div>
              <div className="text-[11px] text-gray-400">已激活热覆盖</div>
            </div>
            <div>
              <div className="text-2xl font-bold text-gray-400">{Math.max(0, ov.prompts.managed - ov.prompts.overrides)}</div>
              <div className="text-[11px] text-gray-400">用代码默认</div>
            </div>
          </div>
          <p className="mt-3 text-[11px] text-gray-400">激活某版经 NATS 热下发各服务，不重启即生效。明细见「提示词」页。</p>
        </div>
      </div>

      {/* C. 全局任务吞吐 */}
      <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
        <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm lg:col-span-2">
          <div className="mb-4 flex items-center justify-between">
            <div>
              <h4 className="text-sm font-semibold text-gray-700">全平台任务吞吐</h4>
              <p className="text-[11px] text-gray-400">近 7 天调度中心处理的任务总数（所有租户/用户）</p>
            </div>
            <span className="rounded bg-violet-50 px-2 py-0.5 text-[10px] font-medium text-violet-700">真实数据</span>
          </div>
          <svg viewBox={`0 0 ${W} ${H}`} className="h-48 w-full overflow-visible">
            <defs>
              <linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#7c3aed" stopOpacity="0.25" />
                <stop offset="100%" stopColor="#7c3aed" stopOpacity="0" />
              </linearGradient>
            </defs>
            <line x1={pad} y1={H - pad} x2={W - pad} y2={H - pad} stroke="#f1f5f9" />
            {areaPath && <path d={areaPath} fill="url(#g)" />}
            {dPath && <path d={dPath} fill="none" stroke="#7c3aed" strokeWidth="2.5" strokeLinecap="round" />}
            {pts.map((p, i) => (
              <g key={i}>
                <circle cx={p.x} cy={p.y} r="4" fill="#fff" stroke="#7c3aed" strokeWidth="2" />
                <title>{`${trend[i].key}: ${trend[i].count} 任务`}</title>
              </g>
            ))}
          </svg>
          <div className="mt-2 flex justify-between px-2 text-[10px] text-gray-400">
            {trend.map((d) => (
              <span key={d.key}>{d.key}</span>
            ))}
          </div>
        </div>

        <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
          <div className="mb-4">
            <h4 className="text-sm font-semibold text-gray-700">任务终态分布</h4>
            <p className="text-[11px] text-gray-400">近 7 天全局终态占比</p>
          </div>
          <div className="space-y-3">
            {ov.status_count.length === 0 && <div className="text-xs text-gray-400">暂无任务</div>}
            {ov.status_count
              .slice()
              .sort((a, b) => b.count - a.count)
              .map((d) => {
                const st = statusStyle(d.key);
                const pct = (d.count / totalStatus) * 100;
                return (
                  <div key={d.key}>
                    <div className="mb-1 flex items-center justify-between text-xs">
                      <span className="flex items-center gap-1.5 text-gray-600">
                        <span className="h-2.5 w-2.5 rounded-full" style={{ backgroundColor: st.color }} />
                        {st.label}
                      </span>
                      <span className="font-semibold text-gray-400">{d.count} · {pct.toFixed(0)}%</span>
                    </div>
                    <div className="h-1.5 w-full overflow-hidden rounded-full bg-gray-100">
                      <div className="h-full rounded-full" style={{ width: `${pct}%`, backgroundColor: st.color }} />
                    </div>
                  </div>
                );
              })}
          </div>
        </div>
      </div>

      {/* D. 系统健康拓扑 */}
      <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
        <div className="mb-4 flex items-center justify-between">
          <div>
            <h4 className="text-sm font-semibold text-gray-700">系统健康拓扑</h4>
            <p className="text-[11px] text-gray-400">基建 + 应用服务 + MCP 工具注册（NATS 实时探活）</p>
          </div>
          <span className="rounded bg-emerald-50 px-2 py-0.5 text-[10px] font-medium text-emerald-700">实时</span>
        </div>
        <div className="grid grid-cols-1 gap-x-8 gap-y-1 sm:grid-cols-2 lg:grid-cols-3">
          <HealthGroup title="基建" items={status.infra.map((i) => ({ name: i.name, up: i.up, detail: i.detail }))} />
          <HealthGroup title="应用服务" items={status.services.map((s) => ({ name: s.name, up: s.up, detail: s.detail }))} />
          <HealthGroup
            title="MCP 工具组"
            items={status.tools.map((t) => ({ name: t.server, up: t.up, detail: `${t.tools?.length ?? 0} 个工具` }))}
          />
        </div>
      </div>
    </div>
  );
}

function Row({ label, children }: { label: string; children: ReactNode }) {
  return (
    <div className="flex items-center justify-between border-b border-gray-50 pb-2 text-xs last:border-0 last:pb-0">
      <span className="text-gray-400">{label}</span>
      <span className="text-right">{children}</span>
    </div>
  );
}

function HealthGroup({ title, items }: { title: string; items: { name: string; up: boolean; detail?: string }[] }) {
  return (
    <div>
      <div className="mb-1 mt-2 text-[10px] font-semibold uppercase tracking-wider text-gray-300">{title}</div>
      {items.map((it) => (
        <div key={it.name} className="flex items-center justify-between border-b border-gray-50 py-1.5 text-xs">
          <span className="flex items-center gap-1.5 text-gray-600">
            <span className={`h-2 w-2 rounded-full ${it.up ? "bg-emerald-500" : "bg-rose-500"}`} />
            {it.name}
          </span>
          <span className={`text-[10px] ${it.up ? "text-gray-400" : "text-rose-500"}`}>{it.up ? it.detail || "在线" : "离线"}</span>
        </div>
      ))}
    </div>
  );
}

type Tone = "violet" | "emerald" | "cyan" | "amber" | "rose";
const TONE: Record<Tone, string> = {
  violet: "bg-violet-50 text-violet-600",
  emerald: "bg-emerald-50 text-emerald-600",
  cyan: "bg-cyan-50 text-cyan-600",
  amber: "bg-amber-50 text-amber-600",
  rose: "bg-rose-50 text-rose-600",
};

function MetricCard({ label, value, sub, icon, tone }: { label: string; value: ReactNode; sub: ReactNode; icon: IconName; tone: Tone }) {
  return (
    <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm transition-shadow hover:shadow-md">
      <div className="flex items-center justify-between">
        <span className="text-xs font-medium text-gray-400">{label}</span>
        <div className={`rounded-lg p-2 ${TONE[tone]}`}>
          <Icon name={icon} className="h-5 w-5" />
        </div>
      </div>
      <div className="mt-4">
        <h3 className="text-2xl font-bold text-gray-800">{value}</h3>
        <p className="mt-1 text-xs">{sub}</p>
      </div>
    </div>
  );
}

type IconName = "tasks" | "award" | "pulse" | "users";
const PATHS: Record<IconName, string> = {
  tasks: "M9 11l3 3L22 4 M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11",
  award: "M12 15a7 7 0 1 0 0-14 7 7 0 0 0 0 14z M8.21 13.89 7 23l5-3 5 3-1.21-9.12",
  pulse: "M22 12h-4l-3 9L9 3l-3 9H2",
  users: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2 M9 7a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M22 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75",
};
function Icon({ name, className }: { name: IconName; className?: string }) {
  return (
    <svg viewBox="0 0 24 24" className={className} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d={PATHS[name]} />
    </svg>
  );
}
