"use client";

/** 批量测试已完成结果视图。 */

import { ChevronDown, ChevronRight, Settings2 } from "lucide-react";
import { useRef, useState } from "react";

import { BatchCaseDetailDrawer } from "@/components/batch-test/batch-case-detail-drawer";
import {
  BatchCaseStatusBadge,
  getBatchCaseStatusLabel,
} from "@/components/batch-test/batch-case-status";
import {
  BATCH_ERROR_STRATEGY_LABEL,
  BATCH_FAILURE_STRATEGY_LABEL,
  countByStatus,
  formatRunDuration,
  formatRunTime,
  type BatchRunSnapshot,
} from "@/data/batch-run";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

type ResultFilter = "all" | "fail" | "error";

function stopReasonLabel(run: BatchRunSnapshot): string {
  if (run.stopReason === "manual") return "已手动停止";
  if (run.stopReason === "assertion_failure") return "因断言失败停止";
  if (run.stopReason === "execution_error") return "因执行错误停止";
  return "";
}

export function BatchRunCompletedView({
  run,
  onEditCase,
  onRerunCase,
}: {
  run: BatchRunSnapshot;
  onEditCase: (caseId: string) => void;
  onRerunCase: (caseId: string) => void;
}) {
  const [selectedCaseId, setSelectedCaseId] = useState<string | null>(null);
  const [filter, setFilter] = useState<ResultFilter>("all");
  const detailRowRefs = useRef(new Map<string, HTMLTableRowElement>());
  const selectedCase =
    run.cases.find((item) => item.id === selectedCaseId) ?? null;
  const detailOpen = Boolean(selectedCase);

  const counts = countByStatus(run.cases);
  const total = run.cases.length;
  const outcome = getRunOutcome(run, counts);
  const visibleCases =
    filter === "fail"
      ? run.cases.filter((item) => item.status === "fail")
      : filter === "error"
        ? run.cases.filter((item) => item.status === "error")
        : run.cases;

  function closeDetail() {
    const currentId = selectedCaseId;
    setSelectedCaseId(null);
    if (!currentId) return;
    window.requestAnimationFrame(() => {
      detailRowRefs.current.get(currentId)?.focus();
    });
  }

  function handleCaseRowKeyDown(
    event: React.KeyboardEvent<HTMLTableRowElement>,
    caseId: string,
  ) {
    if (event.key !== "Enter" && event.key !== " ") return;
    event.preventDefault();
    setSelectedCaseId(caseId);
  }

  return (
    <div className="flex h-full min-h-0 w-full overflow-hidden bg-background">
      <div className="min-h-0 min-w-0 flex-1 overflow-y-auto overscroll-none px-4 py-4 sm:px-6 sm:py-6 lg:px-8">
        <div
          className={cn(
            "flex flex-col gap-4",
            detailOpen ? "w-full" : "mx-auto w-full max-w-[960px]",
          )}
        >
          {/* 结果总览 */}
          <section className="rounded-2xl border border-hairline bg-card p-5 shadow-sm">
            <div className="flex flex-wrap items-start justify-between gap-3">
              <div>
                <h2 className="text-base font-medium text-foreground">
                  {run.title}
                </h2>
                {run.finishedAt && (
                  <p className="mt-1.5 text-xs text-muted-soft">
                    完成于 {formatRunTime(run.finishedAt)}
                    {run.stopReason ? ` · ${stopReasonLabel(run)}` : ""}
                  </p>
                )}
              </div>
              <span
                className={cn(
                  "inline-flex shrink-0 items-center rounded-full px-3 py-1 text-xs font-medium",
                  outcome.className,
                )}
              >
                {outcome.label}
              </span>
            </div>

            <div className="mt-5 rounded-xl border border-hairline bg-canvas-soft/60 p-4">
              <div className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
                <div>
                  <p className="text-xs font-medium tracking-wide text-muted-soft uppercase">
                    测试结果
                  </p>
                  <p className="mt-1 font-display text-3xl text-ink">
                    <span className="tabular-nums">{counts.pass}</span>
                    <span className="mx-1.5 text-muted-soft">/</span>
                    <span className="tabular-nums">{total}</span>
                    <span className="ml-2 text-2xl">通过</span>
                  </p>
                </div>

                <div className="grid grid-cols-3 gap-x-5 gap-y-2 text-sm sm:shrink-0">
                  <ResultCount tone="success" label="通过" count={counts.pass} />
                  <ResultCount
                    tone="destructive"
                    label="断言失败"
                    count={counts.fail}
                  />
                  <ResultCount
                    tone="warning"
                    label="执行错误"
                    count={counts.error}
                  />
                  {counts.skipped > 0 && (
                    <ResultCount
                      tone="muted"
                      label="未执行"
                      count={counts.skipped}
                    />
                  )}
                </div>
              </div>

              <ResultDistribution counts={counts} total={total} />
            </div>

            <dl
              className={cn(
                "mt-4 grid gap-x-6 gap-y-4 text-sm sm:grid-cols-2",
                !detailOpen && "lg:grid-cols-4",
              )}
            >
              <div>
                <dt className="text-xs text-muted-foreground">被测助手</dt>
                <dd className="mt-1 break-words font-medium text-foreground">
                  {run.assistantName}
                </dd>
              </div>
              <div className="min-w-0">
                <dt className="text-xs text-muted-foreground">评估模型</dt>
                <dd
                  className="mt-1 break-words font-medium text-foreground"
                  title={run.config.evaluatorModelResourceName}
                >
                  {run.config.evaluatorModelResourceName}
                </dd>
                {run.config.evaluatorModel && (
                  <dd
                    className="mt-0.5 break-all font-mono text-[11px] text-muted-soft"
                    title={run.config.evaluatorModel}
                  >
                    {run.config.evaluatorModel}
                  </dd>
                )}
              </div>
              <div>
                <dt className="text-xs text-muted-foreground">测试范围</dt>
                <dd className="mt-1 font-medium text-foreground">
                  {run.config.suiteCount} 个测试集 · {total} 个用例
                </dd>
              </div>
              <div>
                <dt className="text-xs text-muted-foreground">运行参数</dt>
                <dd className="mt-1 font-medium text-foreground">
                  {run.config.concurrency} 并发 · {run.config.timeoutSecs} 秒超时
                  <span className="mx-1.5 text-muted-soft">·</span>
                  {formatRunDuration(run.startedAt, run.finishedAt)}
                </dd>
              </div>
            </dl>

            <details className="group mt-4 border-t border-hairline pt-3">
              <summary className="flex w-fit cursor-pointer list-none items-center gap-2 rounded-full px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-canvas-soft hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 [&::-webkit-details-marker]:hidden">
                <Settings2 size={13} />
                查看运行设置
                <ChevronDown
                  size={13}
                  className="transition-transform group-open:rotate-180"
                />
              </summary>
              <div className="mt-3 grid gap-3 rounded-xl border border-hairline bg-canvas-soft/50 px-4 py-3 text-xs leading-5 text-muted-foreground sm:grid-cols-2">
                <p>
                  <span className="font-medium text-foreground">断言失败：</span>
                  {BATCH_FAILURE_STRATEGY_LABEL[run.config.failureStrategy]}
                </p>
                <p>
                  <span className="font-medium text-foreground">执行错误：</span>
                  重试 {run.config.errorRetryCount} 次，
                  {BATCH_ERROR_STRATEGY_LABEL[run.config.errorStrategy]}
                </p>
              </div>
            </details>
          </section>

          {/* 用例列表 */}
          <section className="rounded-2xl border border-hairline bg-card shadow-sm">
            <div className="flex flex-wrap items-center justify-between gap-3 border-b border-hairline px-5 py-3.5">
              <h3 className="text-sm font-medium text-foreground">用例列表</h3>
              <div
                className="flex items-center gap-2"
                role="group"
                aria-label="结果筛选"
              >
                <Button
                  type="button"
                  size="sm"
                  variant={filter === "all" ? "default" : "outline"}
                  className="rounded-full"
                  aria-pressed={filter === "all"}
                  onClick={() => setFilter("all")}
                >
                  全部 {total}
                </Button>
                <Button
                  type="button"
                  size="sm"
                  variant={filter === "fail" ? "default" : "outline"}
                  className="rounded-full"
                  aria-pressed={filter === "fail"}
                  onClick={() => setFilter("fail")}
                >
                  断言失败 {counts.fail}
                </Button>
                <Button
                  type="button"
                  size="sm"
                  variant={filter === "error" ? "default" : "outline"}
                  className="rounded-full"
                  aria-pressed={filter === "error"}
                  onClick={() => setFilter("error")}
                >
                  执行错误 {counts.error}
                </Button>
              </div>
            </div>

            <div className="overflow-x-auto">
              <table className="w-full min-w-[560px] text-left text-sm">
                <thead>
                  <tr className="border-b border-hairline text-xs text-muted-soft">
                    <th className="w-12 px-5 py-2.5 font-medium">#</th>
                    <th className="px-3 py-2.5 font-medium">测试用例</th>
                    <th className="w-28 px-3 py-2.5 font-medium">状态</th>
                    <th className="w-24 px-3 py-2.5 font-medium">详情</th>
                  </tr>
                </thead>
                <tbody>
                  {visibleCases.map((item) => {
                    const index = run.cases.findIndex(
                      (caseItem) => caseItem.id === item.id,
                    );
                    return (
                      <tr
                        key={item.id}
                        ref={(element) => {
                          if (element) {
                            detailRowRefs.current.set(item.id, element);
                          } else {
                            detailRowRefs.current.delete(item.id);
                          }
                        }}
                        role="button"
                        tabIndex={0}
                        aria-label={`查看用例 ${item.name} 详情，状态：${getBatchCaseStatusLabel(item.status)}`}
                        aria-expanded={selectedCaseId === item.id}
                        aria-controls="batch-case-detail"
                        onClick={() => setSelectedCaseId(item.id)}
                        onKeyDown={(event) =>
                          handleCaseRowKeyDown(event, item.id)
                        }
                        className={cn(
                          "cursor-pointer border-b border-hairline transition-colors outline-none last:border-b-0 hover:bg-canvas-soft/70 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/40",
                          selectedCaseId === item.id && "bg-canvas-soft",
                        )}
                      >
                        <td className="w-12 px-5 py-3 tabular-nums text-muted-foreground">
                          {index + 1}
                        </td>
                        <td className="px-3 py-3 font-medium text-foreground">
                          {item.name}
                        </td>
                        <td className="w-28 px-3 py-3">
                          <BatchCaseStatusBadge status={item.status} />
                        </td>
                        <td className="w-24 px-3 py-2">
                          <span className="inline-flex items-center gap-1 text-sm text-muted-foreground">
                            查看
                            <ChevronRight size={14} />
                          </span>
                        </td>
                      </tr>
                    );
                  })}
                  {visibleCases.length === 0 && (
                    <tr>
                      <td
                        colSpan={4}
                        className="px-5 py-10 text-center text-sm text-muted-foreground"
                      >
                        {filter === "error"
                          ? "本次运行没有执行错误。"
                          : "本次运行没有断言失败用例。"}
                      </td>
                    </tr>
                  )}
                </tbody>
              </table>
            </div>
          </section>
        </div>
      </div>

      {selectedCase && (
        <BatchCaseDetailDrawer
          item={selectedCase}
          assistantName={run.assistantName}
          onClose={closeDetail}
          onEdit={() => onEditCase(selectedCase.id)}
          onRerun={() => onRerunCase(selectedCase.id)}
        />
      )}
    </div>
  );
}

type BatchCounts = ReturnType<typeof countByStatus>;

function getRunOutcome(run: BatchRunSnapshot, counts: BatchCounts) {
  if (run.status === "cancelled") {
    return {
      label: "运行已停止",
      className: "bg-surface-strong text-muted-foreground",
    };
  }
  if (counts.error > 0) {
    return {
      label: "存在执行错误",
      className: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
    };
  }
  if (counts.fail > 0) {
    return {
      label: "存在断言失败",
      className: "bg-destructive/10 text-destructive",
    };
  }
  if (counts.skipped > 0) {
    return {
      label: "部分未执行",
      className: "bg-surface-strong text-muted-foreground",
    };
  }
  if (counts.pass > 0) {
    return {
      label: "全部通过",
      className: "bg-success/10 text-success",
    };
  }
  return {
    label: "暂无结果",
    className: "bg-surface-strong text-muted-foreground",
  };
}

function ResultCount({
  tone,
  label,
  count,
}: {
  tone: "success" | "destructive" | "warning" | "muted";
  label: string;
  count: number;
}) {
  const dotClass = {
    success: "bg-success",
    destructive: "bg-destructive",
    warning: "bg-amber-500",
    muted: "bg-muted-soft",
  }[tone];

  return (
    <div className="flex min-w-0 items-center gap-2">
      <span
        className={cn("size-2 shrink-0 rounded-full", dotClass)}
        aria-hidden
      />
      <span className="truncate text-muted-foreground">{label}</span>
      <span className="ml-auto font-medium tabular-nums text-foreground">
        {count}
      </span>
    </div>
  );
}

function ResultDistribution({
  counts,
  total,
}: {
  counts: BatchCounts;
  total: number;
}) {
  const segments = [
    { key: "pass", count: counts.pass, className: "bg-success" },
    { key: "fail", count: counts.fail, className: "bg-destructive" },
    { key: "error", count: counts.error, className: "bg-amber-500" },
    { key: "skipped", count: counts.skipped, className: "bg-muted-soft" },
  ].filter((item) => item.count > 0);

  return (
    <div
      className="mt-4 flex h-2 overflow-hidden rounded-full bg-surface-strong"
      role="img"
      aria-label={`结果分布：通过 ${counts.pass}，断言失败 ${counts.fail}，执行错误 ${counts.error}，未执行 ${counts.skipped}`}
    >
      {total > 0 &&
        segments.map((segment) => (
          <span
            key={segment.key}
            className={segment.className}
            style={{ flexBasis: 0, flexGrow: segment.count }}
            aria-hidden
          />
        ))}
    </div>
  );
}
