"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useDropzone } from "react-dropzone";
import {
  ChevronRight,
  Download,
  FileJson,
  FileText,
  History,
  Loader2,
  Plus,
  Save,
  Sparkles,
  Trash2,
  Upload,
} from "lucide-react";
import DashboardLayout from "@/components/layout/dashboard-layout";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { useToast } from "@/components/ui/use-toast";
import {
  downloadJson,
  loadExtractionDraft,
  parseRequirementJson,
  PriorityLevel,
  RequirementExtractionResult,
  RequirementItem,
  saveExtractionDraft,
} from "@/lib/document-mock";
import {
  createSrsJob,
  deleteSrsJob,
  getSrsJobResult,
  getSrsJobStatus,
  listSrsHistory,
  saveSrsRequirements,
  SrsHistoryItem,
  toExtractionResult,
} from "@/lib/srs-tools-api";
import { buildSectionTree, rebuildRawOutput, SectionTreeNode } from "@/lib/srs-json";
import { cn } from "@/lib/utils";

const formatDateTime = (value: string) => {
  return new Date(value).toLocaleString("zh-CN");
};

const priorityVariant: Record<
  PriorityLevel,
  "default" | "secondary" | "outline"
> = {
  高: "default",
  中: "secondary",
  低: "outline",
};

const normalizeMultiline = (value: string) => {
  return value
    .split("\n")
    .map((entry) => entry.trim())
    .filter((entry) => entry.length > 0);
};

const wait = (ms: number) =>
  new Promise<void>((resolve) => {
    setTimeout(resolve, ms);
  });

const SRS_JOB_POLL_INTERVAL_MS = 2000;
const SRS_JOB_MAX_POLL_COUNT = 900;

const EXTRACTION_JOB_KEY = "doc_processing_extraction_job_id";

const requirementTypeOptions: Array<{
  value: NonNullable<RequirementItem["requirementType"]>;
  label: string;
}> = [
  { value: "functional", label: "功能需求" },
  { value: "interface", label: "接口需求" },
  { value: "performance", label: "性能需求" },
  { value: "security", label: "安全需求" },
  { value: "reliability", label: "可靠性需求" },
  { value: "other", label: "其他需求" },
];

const normalizeRequirementType = (value: unknown): RequirementItem["requirementType"] => {
  if (
    value === "functional" ||
    value === "interface" ||
    value === "performance" ||
    value === "security" ||
    value === "reliability" ||
    value === "other"
  ) {
    return value;
  }
  if (value === "接口需求") {
    return "interface";
  }
  if (value === "性能需求") {
    return "performance";
  }
  if (value === "安全需求") {
    return "security";
  }
  if (value === "可靠性需求") {
    return "reliability";
  }
  if (value === "其他需求") {
    return "other";
  }
  return "functional";
};

const hasInterfaceMetadata = (item: RequirementItem) => {
  const candidates = [item.interfaceName, item.interfaceType, item.dataSource, item.dataDestination];
  return candidates.some((field) => {
    const value = (field || "").trim();
    return Boolean(value) && !["未知", "unknown", "n/a", "-", "--", "无"].includes(value.toLowerCase());
  });
};

const normalizeRequirement = (item: RequirementItem, index: number): RequirementItem => {
  const normalizedType = normalizeRequirementType(item.requirementType);
  const requirementType =
    normalizedType === "interface" || hasInterfaceMetadata(item) ? "interface" : normalizedType;

  return {
    ...item,
    priority: item.priority || "中",
    requirementType,
    sectionNumber: item.sectionNumber || "",
    sectionTitle: item.sectionTitle || "未归类章节",
    sortOrder: typeof item.sortOrder === "number" ? item.sortOrder : index,
    interfaceName: requirementType === "interface" ? item.interfaceName || "" : "",
    interfaceType: requirementType === "interface" ? item.interfaceType || "" : "",
    dataSource: requirementType === "interface" ? item.dataSource || "" : "",
    dataDestination: requirementType === "interface" ? item.dataDestination || "" : "",
  };
};

const normalizeRequirementList = (requirements: RequirementItem[]) =>
  requirements.map((item, index) => ({
    ...normalizeRequirement(item, index),
    sortOrder: index,
  }));

const buildExtractionWithRequirements = (
  extraction: RequirementExtractionResult,
  requirements: RequirementItem[]
): RequirementExtractionResult => {
  const normalized = normalizeRequirementList(requirements);
  return {
    ...extraction,
    requirements: normalized,
    rawOutput: rebuildRawOutput(
      extraction.rawOutput as Record<string, unknown> | undefined,
      normalized,
      extraction.documentName
    ),
  };
};

const normalizeExtractionResult = (
  extraction: RequirementExtractionResult
): RequirementExtractionResult => {
  return buildExtractionWithRequirements(extraction, extraction.requirements);
};

const collectSectionKeys = (nodes: SectionTreeNode[]): string[] => {
  const keys: string[] = [];
  const walk = (node: SectionTreeNode) => {
    keys.push(node.key);
    node.children.forEach((child) => walk(child));
  };
  nodes.forEach((node) => walk(node));
  return keys;
};

const countSectionRequirements = (node: SectionTreeNode): number =>
  node.requirements.length +
  node.children.reduce((total, child) => total + countSectionRequirements(child), 0);

const createRequirementId = (requirements: RequirementItem[]) => {
  const usedIds = new Set(requirements.map((item) => item.id));
  const maxNumber = requirements.reduce((max, item) => {
    const match = item.id.match(/(\d+)$/);
    return match ? Math.max(max, Number(match[1])) : max;
  }, 0);

  let nextNumber = maxNumber + 1;
  let candidate = `REQ-${String(nextNumber).padStart(3, "0")}`;
  while (usedIds.has(candidate)) {
    nextNumber += 1;
    candidate = `REQ-${String(nextNumber).padStart(3, "0")}`;
  }
  return candidate;
};

const findDuplicateRequirementId = (requirements: RequirementItem[]) => {
  const seen = new Set<string>();
  for (const item of requirements) {
    const id = item.id.trim();
    if (seen.has(id)) {
      return id;
    }
    seen.add(id);
  }
  return null;
};

export default function RequirementExtractionPage() {
  const [documentFile, setDocumentFile] = useState<File | null>(null);
  const [extraction, setExtraction] = useState<RequirementExtractionResult | null>(
    null
  );
  const [selectedRequirementId, setSelectedRequirementId] = useState<
    string | null
  >(null);
  const [isExtracting, setIsExtracting] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [activeJobId, setActiveJobId] = useState<number | null>(null);
  const [isImportingJson, setIsImportingJson] = useState(false);
  const [historyItems, setHistoryItems] = useState<SrsHistoryItem[]>([]);
  const [isHistoryLoading, setIsHistoryLoading] = useState(false);
  const [expandedSectionKeys, setExpandedSectionKeys] = useState<string[]>([]);
  const [isHistoryOpen, setIsHistoryOpen] = useState(false);
  const jsonInputRef = useRef<HTMLInputElement>(null);
  const { toast } = useToast();

  const setExtractionAndPersist = useCallback((value: RequirementExtractionResult | null) => {
    if (!value) {
      setExtraction(null);
      return;
    }
    const normalized = normalizeExtractionResult(value);
    setExtraction(normalized);
    saveExtractionDraft(normalized);
  }, []);

  const loadHistory = useCallback(async () => {
    setIsHistoryLoading(true);
    try {
      const items = await listSrsHistory();
      setHistoryItems(items);
    } catch {
      setHistoryItems([]);
    } finally {
      setIsHistoryLoading(false);
    }
  }, []);

  useEffect(() => {
    const storedJobId = window.localStorage.getItem(EXTRACTION_JOB_KEY);
    if (storedJobId) {
      const parsed = Number(storedJobId);
      if (!Number.isNaN(parsed) && parsed > 0) {
        setActiveJobId(parsed);
      }
    }

    const draft = loadExtractionDraft();
    if (!draft) {
      void loadHistory();
      return;
    }

    const normalized = normalizeExtractionResult(draft);
    setExtraction(normalized);
    setSelectedRequirementId(draft.requirements[0]?.id ?? null);
    void loadHistory();
  }, [loadHistory]);

  const onDrop = useCallback((acceptedFiles: File[]) => {
    const first = acceptedFiles[0];
    if (!first) {
      return;
    }
    setDocumentFile(first);
  }, []);

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    maxFiles: 1,
    accept: {
      "application/pdf": [".pdf"],
      "application/vnd.openxmlformats-officedocument.wordprocessingml.document": [
        ".docx",
      ],
    },
  });

  const selectedRequirement = extraction?.requirements.find(
    (item) => item.id === selectedRequirementId
  );

  const sectionTree = useMemo(() => {
    if (!extraction) {
      return [];
    }
    return buildSectionTree(
      extraction.rawOutput as Record<string, unknown> | undefined,
      extraction.requirements
    );
  }, [extraction]);

  useEffect(() => {
    if (!sectionTree.length) {
      setExpandedSectionKeys([]);
      return;
    }
    setExpandedSectionKeys((prev) => {
      if (prev.length > 0) {
        return prev;
      }
      return collectSectionKeys(sectionTree).slice(0, 2);
    });
  }, [sectionTree]);

  const updateRequirement = (
    requirementId: string,
    updater: (item: RequirementItem) => RequirementItem
  ) => {
    let nextSelected = selectedRequirementId;
    setExtraction((prev) => {
      if (!prev) {
        return prev;
      }

      const index = prev.requirements.findIndex((item) => item.id === requirementId);
      if (index < 0) {
        return prev;
      }

      const current = prev.requirements[index];
      const updated = normalizeRequirement(updater(current), index);
      const requirements = [...prev.requirements];
      requirements[index] = {
        ...updated,
        sortOrder: index,
      };

      const next = buildExtractionWithRequirements(prev, requirements);

      saveExtractionDraft(next);

      if (selectedRequirementId === requirementId) {
        nextSelected = updated.id;
      }

      return next;
    });

    if (nextSelected) {
      setSelectedRequirementId(nextSelected);
    }
  };

  const handleAddRequirement = () => {
    if (!extraction) {
      return;
    }

    const base = selectedRequirement ?? extraction.requirements[extraction.requirements.length - 1];
    const newRequirement = normalizeRequirement(
      {
        id: createRequirementId(extraction.requirements),
        description: "",
        priority: "中",
        acceptanceCriteria: ["待补充验收标准"],
        sourceField: base?.sourceField || "手动新增",
        sectionUid: base?.sectionUid,
        sectionNumber: base?.sectionNumber || "",
        sectionTitle: base?.sectionTitle || "未归类章节",
        requirementType: base?.requirementType || "functional",
        interfaceName: "",
        interfaceType: "",
        dataSource: "",
        dataDestination: "",
        sortOrder: extraction.requirements.length,
      },
      extraction.requirements.length
    );
    const next = buildExtractionWithRequirements(extraction, [
      ...extraction.requirements,
      newRequirement,
    ]);

    setExtractionAndPersist(next);
    setSelectedRequirementId(newRequirement.id);
    toast({
      title: "已新增需求",
      description: `已创建 ${newRequirement.id}，可在右侧继续编辑。`,
    });
  };

  const handleDeleteRequirement = () => {
    if (!extraction || !selectedRequirement) {
      return;
    }

    const confirmed = window.confirm(`确认删除需求 ${selectedRequirement.id}？`);
    if (!confirmed) {
      return;
    }

    const currentIndex = extraction.requirements.findIndex(
      (item) => item.id === selectedRequirement.id
    );
    if (currentIndex < 0) {
      return;
    }
    const remaining = extraction.requirements.filter((_, index) => index !== currentIndex);
    const next = buildExtractionWithRequirements(extraction, remaining);
    const nextSelected =
      remaining[currentIndex]?.id || remaining[currentIndex - 1]?.id || remaining[0]?.id || null;

    setExtractionAndPersist(next);
    setSelectedRequirementId(nextSelected);
    toast({
      title: "已删除需求",
      description: `${selectedRequirement.id} 已从当前需求文件中移除。`,
    });
  };

  const handleExtract = async () => {
    if (!documentFile) {
      toast({
        title: "请先上传文档",
        description: "支持 Word/PDF 文件上传后再执行需求提取。",
        variant: "destructive",
      });
      return;
    }

    setIsExtracting(true);
    try {
      const job = await createSrsJob(documentFile);
      setActiveJobId(job.job_id);
      window.localStorage.setItem(EXTRACTION_JOB_KEY, String(job.job_id));

      let finalResult: RequirementExtractionResult | null = null;
      for (let i = 0; i < SRS_JOB_MAX_POLL_COUNT; i += 1) {
        const status = await getSrsJobStatus(job.job_id);
        if (status.status === "completed") {
          const rawResult = await getSrsJobResult(job.job_id);
          finalResult = normalizeExtractionResult(toExtractionResult(rawResult));
          break;
        }
        if (status.status === "failed") {
          throw new Error(status.error_message || "需求提取任务失败");
        }
        await wait(SRS_JOB_POLL_INTERVAL_MS);
      }

      if (!finalResult) {
        await loadHistory();
        toast({
          title: "提取仍在后台处理中",
          description: "当前文档较大，任务尚未完成。稍后可在历史记录中加载结果。",
        });
        return;
      }

      setExtractionAndPersist(finalResult);
      setSelectedRequirementId(finalResult.requirements[0]?.id ?? null);
      await loadHistory();
      toast({
        title: "提取完成",
        description: `已生成 ${finalResult.requirements.length} 条需求项。`,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "提取失败，请重试";
      toast({
        title: "提取失败",
        description: message,
        variant: "destructive",
      });
    } finally {
      setIsExtracting(false);
    }
  };

  const handleImportJson = async (
    event: React.ChangeEvent<HTMLInputElement>
  ) => {
    const file = event.target.files?.[0];
    if (!file) {
      return;
    }

    setIsImportingJson(true);
    try {
      const content = await file.text();
      const parsed = normalizeExtractionResult(parseRequirementJson(content));
      setExtractionAndPersist(parsed);
      setSelectedRequirementId(parsed.requirements[0]?.id ?? null);
      setActiveJobId(null);
      window.localStorage.removeItem(EXTRACTION_JOB_KEY);
      toast({
        title: "导入成功",
        description: `已加载 ${parsed.requirements.length} 条需求项。`,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "JSON 文件解析失败";
      toast({
        title: "导入失败",
        description: message,
        variant: "destructive",
      });
    } finally {
      setIsImportingJson(false);
      event.target.value = "";
    }
  };

  const handleSaveDraft = () => {
    if (!extraction) {
      return;
    }

    const normalized = normalizeExtractionResult(extraction);
    const emptyId = normalized.requirements.some((item) => !item.id.trim());
    if (emptyId) {
      toast({
        title: "保存失败",
        description: "需求编号不能为空，请补充后再保存。",
        variant: "destructive",
      });
      return;
    }

    const duplicateId = findDuplicateRequirementId(normalized.requirements);
    if (duplicateId) {
      toast({
        title: "保存失败",
        description: `需求编号 ${duplicateId} 重复，请调整后再保存。`,
        variant: "destructive",
      });
      return;
    }

    const persist = async () => {
      if (!activeJobId) {
        setExtractionAndPersist(normalized);
        toast({
          title: "保存成功",
          description: "当前需求编辑结果已保存到本地。",
        });
        return;
      }

      setIsSaving(true);
      try {
        const saved = await saveSrsRequirements(activeJobId, normalized);
        const next = normalizeExtractionResult(toExtractionResult(saved));
        setExtractionAndPersist(next);
        await loadHistory();
        toast({
          title: "保存成功",
          description: "修改内容已保存到服务端。",
        });
      } catch (error) {
        const message = error instanceof Error ? error.message : "保存失败，请稍后重试";
        toast({
          title: "保存失败",
          description: message,
          variant: "destructive",
        });
      } finally {
        setIsSaving(false);
      }
    };

    void persist();
  };

  const handleExportJson = () => {
    if (!extraction) {
      return;
    }

    const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
    const payload = rebuildRawOutput(
      extraction.rawOutput as Record<string, unknown> | undefined,
      extraction.requirements,
      extraction.documentName
    );
    downloadJson(`requirements-${timestamp}.json`, payload);
    toast({
      title: "导出成功",
      description: "JSON 文件已下载。",
    });
  };

  const toggleSection = (sectionKey: string) => {
    setExpandedSectionKeys((prev) =>
      prev.includes(sectionKey)
        ? prev.filter((key) => key !== sectionKey)
        : [...prev, sectionKey]
    );
  };

  const handleLoadHistoryItem = async (jobId: number) => {
    try {
      const result = await getSrsJobResult(jobId);
      const normalized = normalizeExtractionResult(toExtractionResult(result));
      setExtractionAndPersist(normalized);
      setSelectedRequirementId(normalized.requirements[0]?.id ?? null);
      setActiveJobId(jobId);
      window.localStorage.setItem(EXTRACTION_JOB_KEY, String(jobId));
      setIsHistoryOpen(false);
      toast({
        title: "加载成功",
        description: `已加载 ${normalized.documentName}`,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "加载历史文件失败";
      toast({
        title: "加载失败",
        description: message,
        variant: "destructive",
      });
    }
  };

  const handleDeleteHistoryItem = async (jobId: number) => {
    try {
      await deleteSrsJob(jobId);
      if (activeJobId === jobId) {
        setActiveJobId(null);
        window.localStorage.removeItem(EXTRACTION_JOB_KEY);
        setExtraction(null);
        setSelectedRequirementId(null);
      }
      await loadHistory();
      toast({
        title: "删除成功",
        description: "历史文件已删除。",
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "删除历史文件失败";
      toast({
        title: "删除失败",
        description: message,
        variant: "destructive",
      });
    }
  };

  const renderSectionNode = (node: SectionTreeNode) => {
    const expanded = expandedSectionKeys.includes(node.key);
    const requirementCount = countSectionRequirements(node);
    const sectionLabel =
      `${node.sectionNumber ? `${node.sectionNumber} ` : ""}${node.sectionTitle}`.trim() ||
      "未归类章节";
    return (
      <div key={node.key} className="space-y-2">
        <button
          className="flex w-full items-center gap-2 rounded-md px-2 py-1 text-left hover:bg-muted"
          onClick={() => toggleSection(node.key)}
        >
          <ChevronRight
            className={cn("h-4 w-4 text-muted-foreground transition-transform", expanded && "rotate-90")}
          />
          <div className="flex flex-1 items-center justify-between gap-2">
            <p className="text-sm font-medium">{sectionLabel}</p>
            <Badge variant="outline">{requirementCount}</Badge>
          </div>
        </button>

        {expanded && (
          <div className="space-y-2 border-l pl-4">
            {node.requirements.map((item) => {
              const active = item.id === selectedRequirementId;
              return (
                <button
                  key={`${node.key}-${item.id}`}
                  onClick={() => setSelectedRequirementId(item.id)}
                  className={cn(
                    "w-full rounded-lg border p-3 text-left transition-colors",
                    active ? "border-primary bg-primary/5" : "hover:border-primary/40"
                  )}
                >
                  <div className="flex items-center justify-between gap-2">
                    <p className="font-medium text-sm line-clamp-1">{item.id}</p>
                    <Badge variant={priorityVariant[item.priority]}>{item.priority}</Badge>
                  </div>
                  <p className="mt-1 text-xs text-muted-foreground line-clamp-2">
                    {item.description}
                  </p>
                  <p className="mt-2 text-[11px] text-muted-foreground">{item.id}</p>
                </button>
              );
            })}

            {node.children.map((child) => renderSectionNode(child))}
          </div>
        )}
      </div>
    );
  };

  return (
    <DashboardLayout>
      <div className="space-y-6">
        <Card>
          <CardHeader>
            <CardTitle className="text-2xl">文档处理 · 需求提取</CardTitle>
            <CardDescription>
              上传 Word/PDF 文档后执行需求提取，可按字段查看、修改并保存。
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            <div
              {...getRootProps()}
              className={cn(
                "rounded-lg border-2 border-dashed p-8 text-center transition-colors",
                isDragActive
                  ? "border-primary bg-primary/5"
                  : "border-border hover:border-primary/40"
              )}
            >
              <input {...getInputProps()} />
              <Upload className="mx-auto h-10 w-10 text-muted-foreground" />
              <p className="mt-3 text-sm font-medium">
                拖拽上传 Word/PDF，或点击选择文件
              </p>
              <p className="text-xs text-muted-foreground mt-1">
                支持 .docx / .pdf
              </p>
              {documentFile && (
                <div className="mt-4 inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs">
                  <FileText className="h-3.5 w-3.5" />
                  {documentFile.name}
                </div>
              )}
            </div>

            <div className="flex flex-wrap gap-3">
              <Button onClick={handleExtract} disabled={isExtracting || !documentFile}>
                {isExtracting ? (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                ) : (
                  <Sparkles className="mr-2 h-4 w-4" />
                )}
                开始提取
              </Button>
              <Button
                variant="outline"
                onClick={() => jsonInputRef.current?.click()}
                disabled={isImportingJson}
              >
                {isImportingJson ? (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                ) : (
                  <FileJson className="mr-2 h-4 w-4" />
                )}
                导入 JSON
              </Button>
              <Button
                variant="secondary"
                onClick={handleSaveDraft}
                disabled={!extraction || isSaving}
              >
                {isSaving ? (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                ) : (
                  <Save className="mr-2 h-4 w-4" />
                )}
                保存修改
              </Button>
              <Button variant="outline" onClick={handleExportJson} disabled={!extraction}>
                <Download className="mr-2 h-4 w-4" />
                导出 JSON
              </Button>

              <Dialog open={isHistoryOpen} onOpenChange={setIsHistoryOpen}>
                <DialogTrigger asChild>
                  <Button variant="outline" onClick={() => void loadHistory()}>
                    <History className="mr-2 h-4 w-4" />
                    历史文件
                  </Button>
                </DialogTrigger>
                <DialogContent className="max-w-3xl">
                  <DialogHeader>
                    <DialogTitle>历史提取文件</DialogTitle>
                    <DialogDescription>
                      仅展示通过“开始提取”生成的历史文件，可加载、覆盖保存或删除。
                    </DialogDescription>
                  </DialogHeader>

                  <Table>
                    <TableHeader>
                      <TableRow>
                        <TableHead>文档名称</TableHead>
                        <TableHead>需求数</TableHead>
                        <TableHead>提取时间</TableHead>
                        <TableHead className="text-right">操作</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {isHistoryLoading && (
                        <TableRow>
                          <TableCell colSpan={4} className="text-center text-muted-foreground">
                            正在加载历史文件...
                          </TableCell>
                        </TableRow>
                      )}
                      {!isHistoryLoading && historyItems.length === 0 && (
                        <TableRow>
                          <TableCell colSpan={4} className="text-center text-muted-foreground">
                            暂无历史文件
                          </TableCell>
                        </TableRow>
                      )}
                      {!isHistoryLoading &&
                        historyItems.map((item) => (
                          <TableRow key={item.jobId}>
                            <TableCell>{item.documentName}</TableCell>
                            <TableCell>{item.totalRequirements}</TableCell>
                            <TableCell>{formatDateTime(item.generatedAt)}</TableCell>
                            <TableCell className="text-right">
                              <div className="flex justify-end gap-2">
                                <Button
                                  size="sm"
                                  variant="outline"
                                  onClick={() => void handleLoadHistoryItem(item.jobId)}
                                >
                                  查看
                                </Button>
                                <Button
                                  size="sm"
                                  variant="destructive"
                                  onClick={() => void handleDeleteHistoryItem(item.jobId)}
                                >
                                  <Trash2 className="mr-1 h-3.5 w-3.5" />
                                  删除
                                </Button>
                              </div>
                            </TableCell>
                          </TableRow>
                        ))}
                    </TableBody>
                  </Table>
                </DialogContent>
              </Dialog>

              <input
                ref={jsonInputRef}
                type="file"
                accept="application/json,.json"
                className="hidden"
                onChange={handleImportJson}
              />
            </div>

            {extraction && (
              <div className="text-sm text-muted-foreground">
                文档: {extraction.documentName} · 需求数: {extraction.requirements.length} ·
                更新时间: {formatDateTime(extraction.generatedAt)}
              </div>
            )}
          </CardContent>
        </Card>

        <div className="grid gap-6 lg:grid-cols-[320px_1fr]">
          <Card className="min-h-[500px]">
            <CardHeader>
              <div className="flex items-start justify-between gap-3">
                <div>
                  <CardTitle className="text-lg">需求项树</CardTitle>
                  <CardDescription>按章节层级折叠展开，快速定位需求所属章节</CardDescription>
                </div>
                <Button size="sm" onClick={handleAddRequirement} disabled={!extraction}>
                  <Plus className="mr-1 h-3.5 w-3.5" />
                  新增需求
                </Button>
              </div>
            </CardHeader>
            <CardContent>
              {!extraction && (
                <div className="rounded-lg border border-dashed p-6 text-sm text-muted-foreground text-center">
                  暂无需求项，请先上传文档提取或导入 JSON。
                </div>
              )}
              {extraction && (
                <div className="space-y-3 max-h-[520px] overflow-y-auto pr-1">
                  {sectionTree.length === 0 && (
                    <div className="rounded-lg border border-dashed p-6 text-sm text-muted-foreground text-center">
                      需求项为空
                    </div>
                  )}
                  {sectionTree.map((node) => renderSectionNode(node))}
                </div>
              )}
            </CardContent>
          </Card>

          <Card className="min-h-[500px]">
            <CardHeader>
              <div className="flex items-start justify-between gap-3">
                <div>
                  <CardTitle className="text-lg">需求详情编辑</CardTitle>
                  <CardDescription>支持接口需求开关与字段级编辑，保存后可覆盖历史记录</CardDescription>
                </div>
                <Button
                  size="sm"
                  variant="destructive"
                  onClick={handleDeleteRequirement}
                  disabled={!selectedRequirement}
                >
                  <Trash2 className="mr-1 h-3.5 w-3.5" />
                  删除需求
                </Button>
              </div>
            </CardHeader>
            <CardContent>
              {!selectedRequirement && (
                <div className="rounded-lg border border-dashed p-6 text-sm text-muted-foreground text-center">
                  请选择左侧需求项。
                </div>
              )}

              {selectedRequirement && (
                <div className="space-y-4">
                  <div className="space-y-2">
                    <Label htmlFor="req-id">需求编号</Label>
                    <Input
                      id="req-id"
                      value={selectedRequirement.id}
                      onChange={(event) =>
                        updateRequirement(selectedRequirement.id, (item) => ({
                          ...item,
                          id: event.target.value,
                        }))
                      }
                    />
                  </div>

                  <div className="grid gap-4 md:grid-cols-2">
                    <div className="space-y-2">
                      <Label htmlFor="req-section-number">章节编号</Label>
                      <Input
                        id="req-section-number"
                        value={selectedRequirement.sectionNumber || ""}
                        onChange={(event) =>
                          updateRequirement(selectedRequirement.id, (item) => ({
                            ...item,
                            sectionNumber: event.target.value,
                          }))
                        }
                      />
                    </div>

                    <div className="space-y-2">
                      <Label htmlFor="req-section-title">章节标题</Label>
                      <Input
                        id="req-section-title"
                        value={selectedRequirement.sectionTitle || ""}
                        onChange={(event) =>
                          updateRequirement(selectedRequirement.id, (item) => ({
                            ...item,
                            sectionTitle: event.target.value,
                          }))
                        }
                      />
                    </div>
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor="req-source-field">来源字段</Label>
                    <Input
                      id="req-source-field"
                      value={selectedRequirement.sourceField || ""}
                      onChange={(event) =>
                        updateRequirement(selectedRequirement.id, (item) => ({
                          ...item,
                          sourceField: event.target.value,
                        }))
                      }
                    />
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor="req-priority">优先级</Label>
                    <select
                      id="req-priority"
                      className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm"
                      value={selectedRequirement.priority}
                      onChange={(event) =>
                        updateRequirement(selectedRequirement.id, (item) => ({
                          ...item,
                          priority: event.target.value as PriorityLevel,
                        }))
                      }
                    >
                      <option value="高">高</option>
                      <option value="中">中</option>
                      <option value="低">低</option>
                    </select>
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor="req-type">需求类型</Label>
                    <select
                      id="req-type"
                      className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm"
                      value={selectedRequirement.requirementType || "functional"}
                      onChange={(event) => {
                        const nextType = event.target.value as NonNullable<
                          RequirementItem["requirementType"]
                        >;
                        updateRequirement(selectedRequirement.id, (item) => ({
                          ...item,
                          requirementType: nextType,
                          interfaceName: nextType === "interface" ? item.interfaceName || "" : "",
                          interfaceType: nextType === "interface" ? item.interfaceType || "" : "",
                          dataSource: nextType === "interface" ? item.dataSource || "" : "",
                          dataDestination:
                            nextType === "interface" ? item.dataDestination || "" : "",
                        }));
                      }}
                    >
                      {requirementTypeOptions.map((option) => (
                        <option key={option.value} value={option.value}>
                          {option.label}
                        </option>
                      ))}
                    </select>
                  </div>

                  <div className="space-y-2">
                    <div className="flex items-center justify-between rounded-md border p-3">
                      <div>
                        <Label htmlFor="is-interface">是否接口需求</Label>
                        <p className="text-xs text-muted-foreground mt-1">
                          开启后可编辑接口名称、接口类型、数据来源和数据目的地。
                        </p>
                      </div>
                      <Switch
                        id="is-interface"
                        checked={selectedRequirement.requirementType === "interface"}
                        onCheckedChange={(checked) =>
                          updateRequirement(selectedRequirement.id, (item) => ({
                            ...item,
                            requirementType: checked ? "interface" : "functional",
                            interfaceName: checked ? item.interfaceName || "" : "",
                            interfaceType: checked ? item.interfaceType || "" : "",
                            dataSource: checked ? item.dataSource || "" : "",
                            dataDestination: checked ? item.dataDestination || "" : "",
                          }))
                        }
                      />
                    </div>
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor="req-description">需求描述</Label>
                    <textarea
                      id="req-description"
                      className="min-h-[120px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
                      value={selectedRequirement.description}
                      onChange={(event) =>
                        updateRequirement(selectedRequirement.id, (item) => ({
                          ...item,
                          description: event.target.value,
                        }))
                      }
                    />
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor="req-acceptance">验收标准（每行一条）</Label>
                    <textarea
                      id="req-acceptance"
                      className="min-h-[140px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
                      value={selectedRequirement.acceptanceCriteria.join("\n")}
                      onChange={(event) =>
                        updateRequirement(selectedRequirement.id, (item) => ({
                          ...item,
                          acceptanceCriteria: normalizeMultiline(event.target.value),
                        }))
                      }
                    />
                  </div>

                  {selectedRequirement.requirementType === "interface" && (
                    <>
                      <div className="space-y-2">
                        <Label htmlFor="req-interface-name">接口名称</Label>
                        <Input
                          id="req-interface-name"
                          value={selectedRequirement.interfaceName || ""}
                          onChange={(event) =>
                            updateRequirement(selectedRequirement.id, (item) => ({
                              ...item,
                              interfaceName: event.target.value,
                            }))
                          }
                        />
                      </div>

                      <div className="space-y-2">
                        <Label htmlFor="req-interface-type">接口类型</Label>
                        <Input
                          id="req-interface-type"
                          value={selectedRequirement.interfaceType || ""}
                          onChange={(event) =>
                            updateRequirement(selectedRequirement.id, (item) => ({
                              ...item,
                              interfaceType: event.target.value,
                            }))
                          }
                        />
                      </div>

                      <div className="space-y-2">
                        <Label htmlFor="req-data-source">数据来源</Label>
                        <Input
                          id="req-data-source"
                          value={selectedRequirement.dataSource || ""}
                          onChange={(event) =>
                            updateRequirement(selectedRequirement.id, (item) => ({
                              ...item,
                              dataSource: event.target.value,
                            }))
                          }
                        />
                      </div>

                      <div className="space-y-2">
                        <Label htmlFor="req-data-destination">数据目的地</Label>
                        <Input
                          id="req-data-destination"
                          value={selectedRequirement.dataDestination || ""}
                          onChange={(event) =>
                            updateRequirement(selectedRequirement.id, (item) => ({
                              ...item,
                              dataDestination: event.target.value,
                            }))
                          }
                        />
                      </div>
                    </>
                  )}
                </div>
              )}
            </CardContent>
          </Card>
        </div>
      </div>
    </DashboardLayout>
  );
}
