import { useMemo } from "react";
import { Users, Wrench, Network } from "lucide-react";
import { deriveTeam, teamNow, type RunPhase, type TeamSeat } from "../lib/run";
import type { ExecEvent } from "../lib/api";
import { cn } from "../ui";

// 团队视图：把多智能体协调画成「协调者居中 + 专家工位环绕」。
// 只有活跃的东西才动（动效=状态编码，不是装饰），并带 prefers-reduced-motion 守卫。
// 数据全部来自现有执行事件流（agent:/tool:/coordinator: 节点），零后端改动。

const W = 680;
const H = 340;
const CX = 340;
const CY = 168;
const HUB_W = 210;
const HUB_H = 120;
const RX = 250; // 工位环绕椭圆半径
const RY = 115;
const SEAT_W = 152;
const SEAT_H = 64;
const RADIAL_MAX = 6; // 超过则降级为列表（环绕会挤）

function seatPos(i: number, n: number) {
  const deg = 180 + (i * 360) / n; // 从左开始顺时针均分
  const rad = (deg * Math.PI) / 180;
  return { x: CX + RX * Math.cos(rad), y: CY + RY * Math.sin(rad) };
}

function truncate(s: string | undefined, n: number): string {
  if (!s) return "";
  return s.length > n ? s.slice(0, n) + "…" : s;
}

function fmtMs(ms?: number): string {
  if (ms == null) return "";
  return ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${ms}ms`;
}

// 工位状态 → 语义色（Tailwind fill/stroke 工具类，跟随主题）。
function seatTone(s: TeamSeat) {
  if (s.status === "error") return { stroke: "stroke-danger/60", dot: "fill-danger", text: "text-danger", label: "失败" };
  if (s.status === "running") return { stroke: "stroke-brand/60", dot: "fill-brand", text: "text-brand-400", label: "工作中" };
  return { stroke: "stroke-line", dot: "fill-success", text: "text-success", label: "已回报" };
}

function SeatCard({ seat }: { seat: TeamSeat }) {
  const t = seatTone(seat);
  const running = seat.status === "running";
  const Icon = seat.kind === "agent" ? Users : Wrench;
  const desc = seat.brief ? `简报：${truncate(seat.brief, 22)}` : truncate(seat.output, 26);
  return (
    <foreignObject x={0} y={0} width={SEAT_W} height={SEAT_H}>
      <div className={cn("h-full rounded-xl border bg-ink-850 px-3 py-2", running ? "border-brand/50" : seat.status === "error" ? "border-danger/50" : "border-line")}>
        <div className="flex items-center gap-1.5">
          <span className={cn("relative flex h-2 w-2 shrink-0 items-center justify-center")}>
            {running && <span className="sdx-ping absolute h-2 w-2 rounded-full bg-brand/60" />}
            <span className={cn("h-1.5 w-1.5 rounded-full", running ? "bg-brand" : seat.status === "error" ? "bg-danger" : "bg-success")} />
          </span>
          <Icon className="h-3 w-3 shrink-0 text-slate-500" strokeWidth={1.8} />
          <span className="truncate text-[12px] font-medium text-slate-100">{seat.name}</span>
          <span className={cn("ml-auto shrink-0 text-[10px] tabular-nums", t.text)}>{running ? "…" : fmtMs(seat.ms)}</span>
        </div>
        <div className="mt-1 line-clamp-2 text-[10px] leading-snug text-slate-500">{desc || t.label}</div>
      </div>
    </foreignObject>
  );
}

export function TeamView({ events, output, phase }: { events: ExecEvent[]; output?: string; phase?: RunPhase }) {
  const team = useMemo(() => deriveTeam(events, teamNow(events, phase === "streaming")), [events, phase]);
  const { lead, seats, t0, t1 } = team;
  const span = Math.max(t1 - t0, 1);
  const streaming = phase === "streaming";
  // 协调者思考流：取 token 流尾部（滚动窗口，避免撑爆布局）。
  const thinking = truncate((output ?? "").slice(-90).replace(/\s+/g, " "), 90);

  if (seats.length === 0 && !lead) {
    return <div className="p-6 text-center text-xs text-slate-600">暂无协调轨迹。</div>;
  }

  const radial = seats.length > 0 && seats.length <= RADIAL_MAX;

  return (
    <div className="flex h-full min-h-0 flex-col overflow-auto">
      <style>{`
        @keyframes sdx-flow{to{stroke-dashoffset:-20}}
        @keyframes sdx-ping{0%{transform:scale(1);opacity:.6}70%,100%{transform:scale(2.8);opacity:0}}
        @keyframes sdx-blink{50%{opacity:0}}
        .sdx-flow{stroke-dasharray:5 5;animation:sdx-flow 1.1s linear infinite}
        .sdx-ping{animation:sdx-ping 1.8s ease-out infinite}
        .sdx-caret{animation:sdx-blink 1.05s step-end infinite}
        @media(prefers-reduced-motion:reduce){.sdx-flow,.sdx-ping,.sdx-caret{animation:none}}
      `}</style>

      {radial ? (
        <svg viewBox={`0 0 ${W} ${H}`} className="w-full shrink-0" role="img" aria-label="团队视图：协调者与专家工位">
          {seats.map((s, i) => {
            const p = seatPos(i, seats.length);
            const running = s.status === "running";
            return (
              <line
                key={`l-${s.node}`}
                x1={CX} y1={CY} x2={p.x} y2={p.y}
                strokeWidth={running ? 1.5 : 1}
                className={cn(running ? "stroke-brand/70 sdx-flow" : s.status === "error" ? "stroke-danger/40" : "stroke-line")}
              />
            );
          })}

          <foreignObject x={CX - HUB_W / 2} y={CY - HUB_H / 2} width={HUB_W} height={HUB_H}>
            <div className="h-full rounded-xl border border-brand/40 bg-ink-850 px-3 py-2.5">
              <div className="flex items-center gap-1.5 text-[11px] text-slate-500">
                <Network className="h-3.5 w-3.5" strokeWidth={1.8} />
                {lead ? "协调者" : "任务产出"}
              </div>
              <div className="mt-1 truncate text-[13px] font-medium text-slate-100">{lead?.label ?? "多智能体任务"}</div>
              <div className="mt-1.5 border-t border-line pt-1.5">
                <div className={cn("text-[11px]", streaming ? "text-brand-400" : "text-slate-500")}>
                  {lead
                    ? streaming
                      ? "综合中…"
                      : lead.status === "error"
                        ? "协调失败"
                        : lead.status === "done"
                          ? "已综合"
                          : "协调中"
                    : streaming
                      ? "生成中…"
                      : "已产出"}
                </div>
                <div className="mt-0.5 line-clamp-2 text-[10px] leading-snug text-slate-500">
                  {thinking || lead?.detail || ""}
                  {streaming && <span className="sdx-caret ml-0.5 text-brand-400">▌</span>}
                </div>
              </div>
            </div>
          </foreignObject>

          {seats.map((s, i) => {
            const p = seatPos(i, seats.length);
            return (
              <g key={s.node} transform={`translate(${p.x - SEAT_W / 2}, ${p.y - SEAT_H / 2})`}>
                <SeatCard seat={s} />
              </g>
            );
          })}
        </svg>
      ) : (
        <div className="grid grid-cols-2 gap-2 p-2">
          {seats.map((s) => (
            <div key={s.node} className="h-16">
              <svg viewBox={`0 0 ${SEAT_W} ${SEAT_H}`} className="h-full w-full" role="img" aria-label={s.name}>
                <SeatCard seat={s} />
              </svg>
            </div>
          ))}
        </div>
      )}

      <div className="shrink-0 border-t border-line px-3 pb-3 pt-2">
        <div className="mb-1.5 text-[11px] text-slate-600">并发时间轴 · 共 {fmtMs(span)}</div>
        <div className="space-y-1">
          {seats.map((s) => {
            const left = ((s.startTS - t0) / span) * 100;
            const width = Math.max((((s.endTS ?? t1) - s.startTS) / span) * 100, 2);
            const running = s.status === "running";
            return (
              <div key={s.node} className="grid grid-cols-[80px_1fr] items-center gap-2">
                <span className="truncate text-[11px] text-slate-500">{s.name}</span>
                <div className="h-1.5 rounded-full bg-ink-800">
                  <div
                    className={cn("h-1.5 rounded-full", running ? "bg-brand" : s.status === "error" ? "bg-danger" : "bg-success")}
                    style={{ marginLeft: `${left}%`, width: `${width}%` }}
                  />
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}
