import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
  App,
  Breadcrumb,
  Button,
  Card,
  Descriptions,
  Empty,
  Input,
  Modal,
  Spin,
  Table,
  Tooltip,
} from "antd";
import { DeleteOutlined, DownloadOutlined, EditOutlined, EyeOutlined, PlusOutlined } from "@ant-design/icons";
import { useNavigate, useParams } from "react-router";
import DetailHeader from "@/components/DetailHeader";
import { SearchControls } from "@/components/SearchControls";
import {
  createKnowledgeDirectoryUsingPost,
  deleteKnowledgeDirectoryUsingDelete,
  deleteKnowledgeItemByIdUsingDelete,
  deleteKnowledgeSetByIdUsingDelete,
  downloadKnowledgeItemFileUsingGet,
  convertKnowledgeItemPreviewUsingPost,
  exportKnowledgeItemsUsingGet,
  queryKnowledgeDirectoriesUsingGet,
  queryKnowledgeItemsUsingGet,
  queryKnowledgeItemPreviewStatusUsingGet,
  queryKnowledgeSetByIdUsingGet,
  updateKnowledgeSetByIdUsingPut,
} from "../knowledge-management.api";
import {
  createDatasetTagUsingPost,
  queryDatasetTagsUsingGet,
} from "../../DataManagement/dataset.api";
import {
  knowledgeContentTypeOptions,
  knowledgeSourceTypeOptions,
  knowledgeStatusMap,
  mapKnowledgeItem,
  KnowledgeItemView,
} from "../knowledge-management.const";
import {
  KnowledgeItem,
  KnowledgeDirectory,
  KnowledgeSet,
  KnowledgeContentType,
  KnowledgeSourceType,
  KnowledgeStatusType,
} from "../knowledge-management.model";
import CreateKnowledgeSet from "../components/CreateKnowledgeSet";
import KnowledgeItemEditor from "../components/KnowledgeItemEditor";
import ImportKnowledgeItemsDialog from "../components/ImportKnowledgeItemsDialog";
import { formatDate } from "@/utils/unit";
import { File, Folder, Clock } from "lucide-react";
import {
  PREVIEW_TEXT_MAX_LENGTH,
  resolvePreviewFileType,
  truncatePreviewText,
  type PreviewFileType,
} from "@/utils/filePreview";

const PREVIEW_MAX_HEIGHT = 500;
const PREVIEW_MODAL_WIDTH = {
  text: "80vw",
  media: "80vw",
};
const PREVIEW_TEXT_FONT_SIZE = 12;
const PREVIEW_TEXT_PADDING = 12;
const PREVIEW_AUDIO_PADDING = 40;
const OFFICE_FILE_EXTENSIONS = [".doc", ".docx"];
const OFFICE_PREVIEW_POLL_INTERVAL = 2000;
const OFFICE_PREVIEW_POLL_MAX_TIMES = 60;

type OfficePreviewStatus = "UNSET" | "PENDING" | "PROCESSING" | "READY" | "FAILED";

const parseMetadata = (value?: string | Record<string, unknown>) => {
  if (!value) {
    return null;
  }
  if (typeof value === "object") {
    return value as Record<string, unknown>;
  }
  if (typeof value !== "string") {
    return null;
  }
  try {
    const parsed = JSON.parse(value);
    return parsed && typeof parsed === "object" ? (parsed as Record<string, unknown>) : null;
  } catch {
    return null;
  }
};

const isAnnotationItem = (record: KnowledgeItemView) => {
  const metadata = parseMetadata(record.metadata);
  const source = metadata && typeof metadata === "object" ? (metadata as { source?: { type?: string } }).source : null;
  return source?.type === "annotation";
};

const isOfficeFileName = (fileName?: string) => {
  const lowerName = (fileName || "").toLowerCase();
  return OFFICE_FILE_EXTENSIONS.some((ext) => lowerName.endsWith(ext));
};

const normalizeOfficePreviewStatus = (status?: string): OfficePreviewStatus => {
  if (!status) {
    return "UNSET";
  }
  const upper = status.toUpperCase();
  if (upper === "PENDING" || upper === "PROCESSING" || upper === "READY" || upper === "FAILED") {
    return upper as OfficePreviewStatus;
  }
  return "UNSET";
};

type KnowledgeItemRow = KnowledgeItemView & {
  isDirectory?: boolean;
  displayName?: string;
  fullPath?: string;
  fileCount?: number;
};

const PATH_SEPARATOR = "/";
const normalizePath = (value?: string) => (value ?? "").replace(/\\/g, PATH_SEPARATOR);

const normalizePrefix = (value?: string) => {
  const trimmed = normalizePath(value).replace(/^\/+/, "").trim();
  if (!trimmed) {
    return "";
  }
  return trimmed.endsWith(PATH_SEPARATOR) ? trimmed : `${trimmed}${PATH_SEPARATOR}`;
};

const splitRelativePath = (fullPath: string, prefix: string) => {
  if (prefix && !fullPath.startsWith(prefix)) {
    return [];
  }
  const remainder = fullPath.slice(prefix.length);
  return remainder.split(PATH_SEPARATOR).filter(Boolean);
};

const KnowledgeSetDetail = () => {
  const navigate = useNavigate();
  const { message, modal } = App.useApp();
  const { id } = useParams<{ id: string }>();
  const [knowledgeSet, setKnowledgeSet] = useState<KnowledgeSet | null>(null);
  const [showEdit, setShowEdit] = useState(false);
  const [itemEditorOpen, setItemEditorOpen] = useState(false);
  const [currentItem, setCurrentItem] = useState<KnowledgeItem | null>(null);
  const [readItemId, setReadItemId] = useState<string | null>(null);
  const [readModalOpen, setReadModalOpen] = useState(false);
  const [readContent, setReadContent] = useState("");
  const [readTitle, setReadTitle] = useState("");
  const [previewVisible, setPreviewVisible] = useState(false);
  const [previewContent, setPreviewContent] = useState("");
  const [previewFileName, setPreviewFileName] = useState("");
  const [previewFileType, setPreviewFileType] = useState<PreviewFileType>("text");
  const [previewMediaUrl, setPreviewMediaUrl] = useState("");
  const [previewLoadingItemId, setPreviewLoadingItemId] = useState<string | null>(null);
  const [officePreviewStatus, setOfficePreviewStatus] = useState<OfficePreviewStatus | null>(null);
  const [officePreviewError, setOfficePreviewError] = useState("");
  const officePreviewPollingRef = useRef<number | null>(null);
  const officePreviewItemRef = useRef<string | null>(null);

  const [filePrefix, setFilePrefix] = useState("");
  const [fileKeyword, setFileKeyword] = useState("");
  const [itemsLoading, setItemsLoading] = useState(false);
  const [allItems, setAllItems] = useState<KnowledgeItemView[]>([]);
  const [directoriesLoading, setDirectoriesLoading] = useState(false);
  const [allDirectories, setAllDirectories] = useState<KnowledgeDirectory[]>([]);
  const [filePagination, setFilePagination] = useState({
    current: 1,
    pageSize: 10,
  });

  const fetchKnowledgeSet = useCallback(async () => {
    if (!id) return;
    const { data } = await queryKnowledgeSetByIdUsingGet(id);
    setKnowledgeSet(data);
  }, [id]);

  const fetchItems = useCallback(async () => {
    if (!id) {
      setAllItems([]);
      return;
    }
    setItemsLoading(true);
    try {
      const pageSize = 200;
      let page = 1;
      let combined: KnowledgeItemView[] = [];
      const currentPrefix = normalizePrefix(filePrefix);
      const keyword = fileKeyword.trim();
      while (true) {
        const { data } = await queryKnowledgeItemsUsingGet(id, {
          page,
          size: pageSize,
          ...(currentPrefix ? { relativePath: currentPrefix } : {}),
          ...(keyword ? { keyword } : {}),
        });
        const content = Array.isArray(data?.content) ? data.content : [];
        combined = combined.concat(content.map(mapKnowledgeItem));
        if (content.length < pageSize) {
          break;
        }
        if (typeof data?.totalElements === "number" && combined.length >= data.totalElements) {
          break;
        }
        page += 1;
      }
      setAllItems(combined);
    } catch (error) {
      console.error("加载知识条目失败", error);
      message.error("知识条目加载失败");
    } finally {
      setItemsLoading(false);
    }
  }, [fileKeyword, filePrefix, id, message]);

  const fetchDirectories = useCallback(async () => {
    if (!id) {
      setAllDirectories([]);
      return;
    }
    setDirectoriesLoading(true);
    try {
      const currentPrefix = normalizePrefix(filePrefix);
      const keyword = fileKeyword.trim();
      const { data } = await queryKnowledgeDirectoriesUsingGet(id, {
        ...(currentPrefix ? { relativePath: currentPrefix } : {}),
        ...(keyword ? { keyword } : {}),
      });
      const directories = Array.isArray(data) ? data : [];
      setAllDirectories(directories);
    } catch (error) {
      console.error("加载知识目录失败", error);
      message.error("知识目录加载失败");
    } finally {
      setDirectoriesLoading(false);
    }
  }, [fileKeyword, filePrefix, id, message]);

  useEffect(() => {
    fetchKnowledgeSet();
  }, [fetchKnowledgeSet]);

  useEffect(() => {
    if (id) {
      fetchItems();
      fetchDirectories();
    }
  }, [id, fetchItems, fetchDirectories]);

  useEffect(() => {
    setFilePagination((prev) => ({ ...prev, current: 1 }));
  }, [filePrefix, fileKeyword]);

  const isReadOnly =
    knowledgeSet?.status === KnowledgeStatusType.ARCHIVED ||
    knowledgeSet?.status === KnowledgeStatusType.DEPRECATED;

  const handleDeleteSet = async () => {
    if (!knowledgeSet) return;
    await deleteKnowledgeSetByIdUsingDelete(knowledgeSet.id);
    message.success("知识集已删除");
    navigate("/data/knowledge-management");
  };

  const handleDeleteItem = async (item: KnowledgeItemView) => {
    if (!id) return;
    await deleteKnowledgeItemByIdUsingDelete(id, item.id);
    message.success("知识条目已删除");
    fetchItems();
  };

  const handleExportItems = async () => {
    if (!id) return;
    await exportKnowledgeItemsUsingGet(id);
    message.success("知识条目导出成功");
  };

  const isReadableItem = (record: KnowledgeItemView) => {
    if (
      record.contentType === KnowledgeContentType.FILE ||
      record.sourceType === KnowledgeSourceType.FILE_UPLOAD
    ) {
      return false;
    }
    return (
      record.contentType === KnowledgeContentType.TEXT ||
      record.contentType === KnowledgeContentType.MARKDOWN
    );
  };

  const resolveItemRelativePath = useCallback((record: KnowledgeItemView) => {
    const rawPath = record.relativePath || "";
    return normalizePath(rawPath).replace(/^\/+/, "");
  }, []);

  const resolveDirectoryRelativePath = useCallback((directory: KnowledgeDirectory) => {
    const rawPath = directory.relativePath || "";
    return normalizePath(rawPath).replace(/^\/+/, "");
  }, []);

  const resolveDisplayName = useCallback(
    (record: KnowledgeItemView) => {
      const relativePath = resolveItemRelativePath(record);
      if (relativePath) {
        const segments = relativePath.split(PATH_SEPARATOR).filter(Boolean);
        const lastSegment = segments[segments.length - 1];
        if (lastSegment) {
          return lastSegment;
        }
      }
      return record.sourceFileId || "条目";
    },
    [resolveItemRelativePath]
  );

  const resolvePreviewFileName = (record: KnowledgeItemView) => {
    const relativePath = resolveItemRelativePath(record);
    if (relativePath) {
      const segments = relativePath.split(PATH_SEPARATOR).filter(Boolean);
      const lastSegment = segments[segments.length - 1];
      if (lastSegment) {
        return lastSegment;
      }
    }
    if (record.sourceFileId) {
      return record.sourceFileId;
    }
    if (record.content) {
      const segments = record.content.split("/");
      const lastSegment = segments[segments.length - 1];
      if (lastSegment) {
        return lastSegment;
      }
    }
    return "文件";
  };

  const clearOfficePreviewPolling = useCallback(() => {
    if (officePreviewPollingRef.current) {
      window.clearTimeout(officePreviewPollingRef.current);
      officePreviewPollingRef.current = null;
    }
  }, []);

  useEffect(() => {
    return () => {
      clearOfficePreviewPolling();
    };
  }, [clearOfficePreviewPolling]);

  const pollOfficePreviewStatus = useCallback(
    async (setId: string, itemId: string, attempt: number) => {
      clearOfficePreviewPolling();
      officePreviewPollingRef.current = window.setTimeout(async () => {
        if (officePreviewItemRef.current !== itemId) {
          return;
        }
        try {
          const { data } = await queryKnowledgeItemPreviewStatusUsingGet(setId, itemId);
          const status = normalizeOfficePreviewStatus(data?.status);
          if (status === "READY") {
            setPreviewMediaUrl(`/api/data-management/knowledge-sets/${setId}/items/${itemId}/preview`);
            setOfficePreviewStatus("READY");
            setOfficePreviewError("");
            setPreviewLoadingItemId(null);
            fetchItems();
            return;
          }
          if (status === "FAILED") {
            setOfficePreviewStatus("FAILED");
            setOfficePreviewError(data?.previewError || "转换失败，请稍后重试");
            setPreviewLoadingItemId(null);
            fetchItems();
            return;
          }
          if (attempt >= OFFICE_PREVIEW_POLL_MAX_TIMES - 1) {
            setOfficePreviewStatus("FAILED");
            setOfficePreviewError("转换超时，请稍后重试");
            setPreviewLoadingItemId(null);
            return;
          }
          pollOfficePreviewStatus(setId, itemId, attempt + 1);
        } catch (error) {
          console.error("轮询预览状态失败", error);
          if (attempt >= OFFICE_PREVIEW_POLL_MAX_TIMES - 1) {
            setOfficePreviewStatus("FAILED");
            setOfficePreviewError("转换超时，请稍后重试");
            setPreviewLoadingItemId(null);
            return;
          }
          pollOfficePreviewStatus(setId, itemId, attempt + 1);
        }
      }, OFFICE_PREVIEW_POLL_INTERVAL);
    },
    [clearOfficePreviewPolling, fetchItems]
  );

  const handlePreviewItemFile = async (record: KnowledgeItemView) => {
    if (!id) return;
    const fileName = resolvePreviewFileName(record);
    const previewUrl = `/api/data-management/knowledge-sets/${id}/items/${record.id}/preview`;
    setPreviewFileName(fileName);
    setPreviewContent("");
    setPreviewMediaUrl("");

    if (isOfficeFileName(fileName)) {
      setPreviewFileType("pdf");
      setPreviewVisible(true);
      setPreviewLoadingItemId(record.id);
      setOfficePreviewStatus("PROCESSING");
      setOfficePreviewError("");
      officePreviewItemRef.current = record.id;
      try {
        const { data: statusData } = await queryKnowledgeItemPreviewStatusUsingGet(id, record.id);
        const currentStatus = normalizeOfficePreviewStatus(statusData?.status);
        if (currentStatus === "READY") {
          setPreviewMediaUrl(previewUrl);
          setOfficePreviewStatus("READY");
          setPreviewLoadingItemId(null);
          fetchItems();
          return;
        }
        if (currentStatus === "FAILED") {
          setOfficePreviewStatus("PROCESSING");
        }
        if (currentStatus === "PROCESSING") {
          pollOfficePreviewStatus(id, record.id, 0);
          return;
        }
        const { data } = await convertKnowledgeItemPreviewUsingPost(id, record.id);
        const status = normalizeOfficePreviewStatus(data?.status);
        if (status === "READY") {
          setPreviewMediaUrl(previewUrl);
          setOfficePreviewStatus("READY");
          setPreviewLoadingItemId(null);
        } else if (status === "FAILED") {
          setOfficePreviewStatus("FAILED");
          setOfficePreviewError(data?.previewError || "转换失败，请稍后重试");
          setPreviewLoadingItemId(null);
        } else {
          setOfficePreviewStatus("PROCESSING");
          pollOfficePreviewStatus(id, record.id, 0);
        }
        fetchItems();
      } catch (error) {
        console.error("触发预览转换失败", error);
        message.error("触发预览转换失败");
        setOfficePreviewStatus("FAILED");
        setOfficePreviewError("触发预览转换失败");
      } finally {
        setPreviewLoadingItemId(null);
      }
      return;
    }

    const fileType = resolvePreviewFileType(fileName);
    if (!fileType) {
      message.warning("不支持预览该文件类型");
      return;
    }
    setPreviewFileType(fileType);

    if (fileType === "text") {
      setPreviewLoadingItemId(record.id);
      try {
        const response = await fetch(previewUrl);
        if (!response.ok) {
          throw new Error("下载失败");
        }
        const text = await response.text();
        setPreviewContent(truncatePreviewText(text, PREVIEW_TEXT_MAX_LENGTH));
        setPreviewVisible(true);
      } catch (error) {
        console.error("预览知识条目文件失败", error);
        message.error("预览失败，请稍后重试");
      } finally {
        setPreviewLoadingItemId(null);
      }
      return;
    }

    setPreviewMediaUrl(previewUrl);
    setPreviewVisible(true);
  };

  const closePreview = () => {
    clearOfficePreviewPolling();
    officePreviewItemRef.current = null;
    setPreviewVisible(false);
    setPreviewContent("");
    setPreviewMediaUrl("");
    setPreviewFileName("");
    setPreviewFileType("text");
    setOfficePreviewStatus(null);
    setOfficePreviewError("");
  };

  const handleReadItem = async (record: KnowledgeItemView) => {
    if (
      record.contentType === KnowledgeContentType.FILE ||
      record.sourceType === KnowledgeSourceType.FILE_UPLOAD
    ) {
      message.info("该条目为文件，请使用下载查看");
      return;
    }
    setReadItemId(record.id);
    setReadTitle("知识条目");

    if (!record.sourceDatasetId || !record.sourceFileId || isAnnotationItem(record)) {
      const content = record.content || "";
      setReadContent(truncatePreviewText(content, PREVIEW_TEXT_MAX_LENGTH));
      setReadModalOpen(true);
      setReadItemId(null);
      return;
    }

    const fileUrl = `/api/data-management/datasets/${record.sourceDatasetId}/files/${record.sourceFileId}/download`;

    try {
      const response = await fetch(fileUrl);
      if (!response.ok) {
        throw new Error("下载失败");
      }
      const text = await response.text();
      setReadContent(truncatePreviewText(text, PREVIEW_TEXT_MAX_LENGTH));
      setReadModalOpen(true);
    } catch (error) {
      console.error("读取知识条目失败", error);
      message.error("读取失败，请稍后重试");
    } finally {
      setReadItemId(null);
    }
  };

  const handleDownloadItem = async (record: KnowledgeItemView) => {
    if (!id) return;
    try {
      await downloadKnowledgeItemFileUsingGet(id, record.id, record.sourceFileId);
    } catch (error) {
      console.error("下载知识条目文件失败", error);
      message.error("下载失败，请稍后重试");
    }
  };

  const statusMeta = knowledgeSet?.status
    ? knowledgeStatusMap[knowledgeSet.status]
    : undefined;

  const statistics = useMemo(
    () => [
      {
        key: "items",
        icon: <File className="text-blue-400 w-4 h-4" />,
        value: allItems.length,
      },
      {
        key: "updated",
        icon: <Clock className="text-blue-400 w-4 h-4" />,
        value: knowledgeSet?.updatedAt ? formatDate(knowledgeSet.updatedAt) : "-",
      },
    ],
    [allItems.length, knowledgeSet?.updatedAt]
  );

  const handleKeywordChange = (keyword: string) => {
    setFileKeyword(keyword);
  };

  const handleOpenDirectory = (directoryName: string) => {
    const currentPrefix = normalizePrefix(filePrefix);
    const nextPrefix = normalizePrefix(`${currentPrefix}${directoryName}`);
    setFilePrefix(nextPrefix);
  };

  const handleBackToParent = () => {
    const currentPrefix = normalizePrefix(filePrefix);
    if (!currentPrefix) {
      return;
    }
    const trimmed = currentPrefix.replace(/\/$/, "");
    const parts = trimmed.split(PATH_SEPARATOR).filter(Boolean);
    parts.pop();
    const parentPrefix = parts.length ? `${parts.join(PATH_SEPARATOR)}${PATH_SEPARATOR}` : "";
    setFilePrefix(parentPrefix);
  };

  const isInvalidDirectoryName = (value: string) =>
    !value || value.includes("/") || value.includes("\\") || value.includes("..");

  const handleDeleteDirectory = async (directoryName: string) => {
    if (!id) {
      return;
    }
    const currentPrefix = normalizePrefix(filePrefix);
    const directoryPath = normalizePrefix(`${currentPrefix}${directoryName}`).replace(/\/$/, "");
    try {
      await deleteKnowledgeDirectoryUsingDelete(id, directoryPath);
      message.success("文件夹已删除");
      fetchItems();
      fetchDirectories();
    } catch (error) {
      console.error("删除文件夹失败", error);
      message.error("文件夹删除失败");
    }
  };

  const normalizedPrefix = useMemo(() => normalizePrefix(filePrefix), [filePrefix]);

  const { rows: itemRows, total: itemTotal } = useMemo(() => {
    const folderMap = new Map<string, { name: string; fileCount: number }>();
    const fileItems: KnowledgeItemRow[] = [];

    allItems.forEach((item) => {
      const fullPath = resolveItemRelativePath(item);
      if (!fullPath) {
        if (!normalizedPrefix) {
          const displayName = resolveDisplayName(item);
          fileItems.push({
            ...item,
            displayName,
            fullPath: displayName,
          });
        }
        return;
      }
      const segments = splitRelativePath(fullPath, normalizedPrefix);
      if (segments.length === 0) {
        return;
      }
      const leafName = segments[0];

      if (segments.length > 1) {
        const entry = folderMap.get(leafName) || {
          name: leafName,
          fileCount: 0,
        };
        entry.fileCount += 1;
        folderMap.set(leafName, entry);
        return;
      }

      fileItems.push({
        ...item,
        displayName: leafName,
        fullPath,
      });
    });

    allDirectories.forEach((directory) => {
      const fullPath = resolveDirectoryRelativePath(directory);
      if (!fullPath) {
        return;
      }
      const segments = splitRelativePath(fullPath, normalizedPrefix);
      if (segments.length === 0) {
        return;
      }
      const leafName = segments[0];
      if (!folderMap.has(leafName)) {
        folderMap.set(leafName, { name: leafName, fileCount: 0 });
      }
    });

    const folderItems: KnowledgeItemRow[] = Array.from(folderMap.values()).map((entry) => ({
      id: `directory-${normalizedPrefix}${entry.name}`,
      setId: id || "",
      content: "",
      contentType: KnowledgeContentType.FILE,
      status: null,
      rawStatus: KnowledgeStatusType.DRAFT,
      tags: [],
      createdAt: "",
      updatedAt: "",
      sourceType: KnowledgeSourceType.FILE_UPLOAD,
      sourceDatasetId: "",
      sourceFileId: "",
      metadata: "",
      isDirectory: true,
      displayName: entry.name,
      fullPath: `${normalizedPrefix}${entry.name}/`,
      fileCount: entry.fileCount,
    }));

    const sortByName = (a: KnowledgeItemRow, b: KnowledgeItemRow) =>
      (a.displayName || "").localeCompare(b.displayName || "", "zh-Hans-CN");

    folderItems.sort(sortByName);
    fileItems.sort(sortByName);

    const combined = [...folderItems, ...fileItems];
    return { rows: combined, total: combined.length };
  }, [
    allDirectories,
    allItems,
    id,
    normalizedPrefix,
    resolveDisplayName,
    resolveDirectoryRelativePath,
    resolveItemRelativePath,
  ]);

  const pageCurrent = filePagination.current;
  const pageSize = filePagination.pageSize;

  const pagedItemRows = useMemo(() => {
    const startIndex = (pageCurrent - 1) * pageSize;
    const endIndex = startIndex + pageSize;
    return itemRows.slice(startIndex, endIndex);
  }, [itemRows, pageCurrent, pageSize]);

  useEffect(() => {
    const maxPage = Math.max(1, Math.ceil(itemTotal / pageSize));
    if (pageCurrent > maxPage) {
      setFilePagination((prev) => ({ ...prev, current: maxPage }));
    }
  }, [itemTotal, pageCurrent, pageSize]);

  const itemColumns = [
    {
      title: "文件名",
      dataIndex: "sourceFileId",
      key: "sourceFileId",
      fixed: "left" as const,
      width: 260,
      ellipsis: true,
      render: (_: string, record: KnowledgeItemRow) => {
        const displayName = record.displayName || resolveDisplayName(record);
        if (record.isDirectory) {
          return (
            <Button
              type="link"
              onClick={() => handleOpenDirectory(displayName)}
              className="flex items-center gap-2 p-0"
            >
              <Folder className="w-4 h-4 text-blue-500" />
              <span className="truncate">{displayName}</span>
            </Button>
          );
        }
        return (
          <div className="flex items-center gap-2">
            <File className="w-4 h-4 text-gray-800" />
            <span className="truncate">{displayName}</span>
          </div>
        );
      },
    },
    {
      title: "类型",
      dataIndex: "contentType",
      key: "contentType",
      width: 120,
      render: (contentType: string, record: KnowledgeItemRow) => {
        if (record.isDirectory) {
          return "文件夹";
        }
        return (
          knowledgeContentTypeOptions.find((opt) => opt.value === contentType)?.label ||
          contentType
        );
      },
    },
    {
      title: "来源",
      dataIndex: "sourceType",
      key: "sourceType",
      width: 140,
      ellipsis: true,
      render: (sourceType: string, record: KnowledgeItemRow) => {
        if (record.isDirectory) {
          return "-";
        }
        return (
          knowledgeSourceTypeOptions.find((opt) => opt.value === sourceType)?.label ||
          sourceType ||
          "-"
        );
      },
    },
    {
      title: "更新时间",
      dataIndex: "updatedAt",
      key: "updatedAt",
      width: 180,
      ellipsis: true,
      render: (value: string, record: KnowledgeItemRow) =>
        record.isDirectory ? "-" : value || "-",
    },
    {
      title: "操作",
      key: "actions",
      width: 200,
      render: (_: unknown, record: KnowledgeItemRow) => {
        if (record.isDirectory) {
          const displayName = record.displayName || record.sourceFileId || "";
          return (
            <Tooltip title="删除文件夹">
              <Button
                type="text"
                icon={<DeleteOutlined />}
                danger
                onClick={() => {
                  modal.confirm({
                    title: "确认删除该文件夹吗？",
                    content: `删除后将移除文件夹 “${displayName}” 下的全部条目，且无法恢复。`,
                    okText: "删除",
                    okType: "danger",
                    cancelText: "取消",
                    onOk: () => handleDeleteDirectory(displayName),
                  });
                }}
                disabled={isReadOnly}
                aria-label="删除文件夹"
              />
            </Tooltip>
          );
        }
        return (
          <div className="flex items-center gap-2">
            {isReadableItem(record) && (
              <Tooltip title="阅读">
                <Button
                  type="text"
                  icon={<EyeOutlined />}
                  onClick={() => handleReadItem(record)}
                  loading={readItemId === record.id}
                  aria-label="阅读"
                />
              </Tooltip>
            )}
            {(() => {
              const isFileRecord =
                record.contentType === KnowledgeContentType.FILE ||
                record.sourceType === KnowledgeSourceType.FILE_UPLOAD;
              return (
                <>
                  {isFileRecord && (
                    <Tooltip title="预览">
                      <Button
                        type="text"
                        icon={<EyeOutlined />}
                        onClick={() => handlePreviewItemFile(record)}
                        loading={previewLoadingItemId === record.id}
                        aria-label="预览"
                      />
                    </Tooltip>
                  )}
                  {isFileRecord && (
                    <Tooltip title="下载文件">
                      <Button
                        type="text"
                        icon={<DownloadOutlined />}
                        onClick={() => handleDownloadItem(record)}
                        aria-label="下载文件"
                      />
                    </Tooltip>
                  )}
                  {isFileRecord && (
                    <Button
                      type="text"
                      icon={<EditOutlined />}
                      onClick={() => {
                        setCurrentItem({
                          ...(record as unknown as KnowledgeItem),
                          status: record.rawStatus,
                        });
                        setItemEditorOpen(true);
                      }}
                      disabled={
                        isReadOnly ||
                        record.rawStatus === KnowledgeStatusType.ARCHIVED ||
                        record.rawStatus === KnowledgeStatusType.DEPRECATED
                      }
                    />
                  )}
                </>
              );
            })()}
            <Button
              type="text"
              danger
              icon={<DeleteOutlined />}
              onClick={() => handleDeleteItem(record)}
              disabled={isReadOnly}
            />
          </div>
        );
      },
    },
  ];

  return (
    <div className="h-full flex flex-col">
      <div className="mb-4">
        <Breadcrumb>
          <Breadcrumb.Item>
            <a onClick={() => navigate("/data/knowledge-management")}>知识管理</a>
          </Breadcrumb.Item>
          <Breadcrumb.Item>{knowledgeSet?.name || "-"}</Breadcrumb.Item>
        </Breadcrumb>
      </div>

      <DetailHeader
        data={{
          name: knowledgeSet?.name,
          description: knowledgeSet?.description,
          status: statusMeta,
          tags: knowledgeSet?.tags,
        }}
        statistics={statistics}
        operations={[
          {
            key: "edit",
            label: "编辑",
            icon: <EditOutlined />,
            onClick: () => setShowEdit(true),
            danger: false,
          },
          {
            key: "export",
            label: "导出",
            icon: <DownloadOutlined />,
            onClick: handleExportItems,
          },
          {
            key: "delete",
            label: "删除",
            icon: <DeleteOutlined />,
            danger: true,
            confirm: {
              title: "确认删除该知识集吗？",
              description: "删除后将无法恢复，请谨慎操作。",
              cancelText: "取消",
              okText: "删除",
              okType: "danger",
              onConfirm: () => handleDeleteSet(),
            },
          },
        ]}
        tagConfig={{
          showAdd: true,
          tags: knowledgeSet?.tags || [],
          onFetchTags: async () => {
            const res = await queryDatasetTagsUsingGet({
              page: 0,
              pageSize: 1000,
            });
            return res.data || [];
          },
          onCreateAndTag: async (tagName) => {
            const res = await createDatasetTagUsingPost({ name: tagName });
            if (res.data && knowledgeSet) {
              const currentTags = knowledgeSet.tags || [];
              await updateKnowledgeSetByIdUsingPut(knowledgeSet.id, {
                name: knowledgeSet.name,
                description: knowledgeSet.description,
                status: knowledgeSet.status,
                domain: knowledgeSet.domain,
                businessLine: knowledgeSet.businessLine,
                owner: knowledgeSet.owner,
                validFrom: knowledgeSet.validFrom,
                validTo: knowledgeSet.validTo,
                sourceType: knowledgeSet.sourceType,
                sensitivity: knowledgeSet.sensitivity,
                metadata: knowledgeSet.metadata,
                tags: [...currentTags.map((tag) => tag.name), res.data.name],
              });
              fetchKnowledgeSet();
            }
          },
          onAddTag: async (tagName: string) => {
            if (knowledgeSet) {
              const currentTags = knowledgeSet.tags || [];
              const newTagName = tagName?.trim();
              if (!newTagName) return;
              await updateKnowledgeSetByIdUsingPut(knowledgeSet.id, {
                name: knowledgeSet.name,
                description: knowledgeSet.description,
                status: knowledgeSet.status,
                domain: knowledgeSet.domain,
                businessLine: knowledgeSet.businessLine,
                owner: knowledgeSet.owner,
                validFrom: knowledgeSet.validFrom,
                validTo: knowledgeSet.validTo,
                sourceType: knowledgeSet.sourceType,
                sensitivity: knowledgeSet.sensitivity,
                metadata: knowledgeSet.metadata,
                tags: [...currentTags.map((tag) => tag.name), newTagName],
              });
              fetchKnowledgeSet();
            }
          },
        }}
      />

        <CreateKnowledgeSet
          showBtn={false}
          isEdit={showEdit}
          data={knowledgeSet}
          onUpdate={() => {
            setShowEdit(false);
            fetchKnowledgeSet();
          }}
          onClose={() => setShowEdit(false)}
        />

      <Card className="mt-4">
        <Descriptions column={2} size="small">
          <Descriptions.Item label="领域">{knowledgeSet?.domain || "-"}</Descriptions.Item>
          <Descriptions.Item label="业务线">{knowledgeSet?.businessLine || "-"}</Descriptions.Item>
          <Descriptions.Item label="负责人">{knowledgeSet?.owner || "-"}</Descriptions.Item>
          {/* <Descriptions.Item label="敏感级别">{knowledgeSet?.sensitivity || "-"}</Descriptions.Item> */}
          <Descriptions.Item label="有效期">
            {knowledgeSet?.validFrom || "-"} ~ {knowledgeSet?.validTo || "-"}
          </Descriptions.Item>
          <Descriptions.Item label="来源类型">{knowledgeSet?.sourceType || "-"}</Descriptions.Item>
        </Descriptions>
      </Card>

      <div className="flex-1 border-card p-6 mt-4">
        <div className="flex items-center justify-between mb-4 gap-3">
          <SearchControls
            searchTerm={fileKeyword}
            onSearchChange={handleKeywordChange}
            searchPlaceholder="搜索文件名或目录"
            filters={[]}
            onFiltersChange={() => {}}
            onClearFilters={() => setFileKeyword("")}
            showViewToggle={false}
            showReload={false}
          />
          <div className="flex items-center gap-2">
            <Button
              onClick={() => {
                let dirName = "";
                modal.confirm({
                  title: "新建文件夹",
                  content: (
                    <Input
                      autoFocus
                      placeholder="请输入文件夹名称"
                      onChange={(event) => {
                        dirName = event.target.value?.trim();
                      }}
                    />
                  ),
                  okText: "确定",
                  cancelText: "取消",
                  onOk: async () => {
                    if (isInvalidDirectoryName(dirName)) {
                      message.warning("请输入合法的文件夹名称");
                      return Promise.reject();
                    }
                    if (!id) {
                      return Promise.reject();
                    }
                    const currentPrefix = normalizePrefix(filePrefix);
                    try {
                      await createKnowledgeDirectoryUsingPost(id, {
                        parentPrefix: currentPrefix,
                        directoryName: dirName,
                      });
                      message.success("文件夹已创建");
                      const nextPrefix = normalizePrefix(`${currentPrefix}${dirName}`);
                      setFilePrefix(nextPrefix);
                    } catch (error) {
                      console.error("创建文件夹失败", error);
                      message.error("创建文件夹失败");
                      return Promise.reject();
                    }
                  },
                });
              }}
              disabled={isReadOnly}
            >
              新建文件夹
            </Button>
            <Button
              type="primary"
              icon={<PlusOutlined />}
              onClick={() => {
                setCurrentItem(null);
                setItemEditorOpen(true);
              }}
              disabled={isReadOnly}
            >
              新建条目
            </Button>
            <ImportKnowledgeItemsDialog
              setId={id || ""}
              onImported={fetchItems}
              disabled={isReadOnly}
            />
          </div>
        </div>

        <div className="mb-2">
          {normalizedPrefix && (
            <Button type="link" onClick={handleBackToParent} className="p-0">
              <span className="flex items-center text-blue-500">
                <svg
                  className="w-4 h-4 mr-1"
                  fill="none"
                  stroke="currentColor"
                  viewBox="0 0 24 24"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth={2}
                    d="M10 19l-7-7m0 0l7-7m-7 7h18"
                  />
                </svg>
                返回上一级
              </span>
            </Button>
          )}
          {normalizedPrefix && (
            <span className="ml-2 text-gray-600">当前路径: {normalizedPrefix}</span>
          )}
        </div>

        {itemRows.length === 0 ? (
          <Empty description="暂无知识条目" />
        ) : (
          <Table
            loading={itemsLoading || directoriesLoading}
            columns={itemColumns}
            dataSource={pagedItemRows}
            rowKey="id"
            pagination={{
              current: filePagination.current,
              pageSize: filePagination.pageSize,
              total: itemTotal,
              showTotal: (total) => `共 ${total} 条`,
              onChange: (page, pageSize) =>
                setFilePagination({
                  current: page,
                  pageSize: pageSize || filePagination.pageSize,
                }),
            }}
            scroll={{ y: "calc(100vh - 36rem)" }}
          />
        )}
      </div>

      <KnowledgeItemEditor
        open={itemEditorOpen}
        setId={id || ""}
        data={currentItem}
        parentPrefix={normalizedPrefix}
        readOnly={isReadOnly}
        onCancel={() => {
          setItemEditorOpen(false);
          setCurrentItem(null);
        }}
        onSuccess={() => {
          setItemEditorOpen(false);
          setCurrentItem(null);
          fetchItems();
        }}
      />

      <Modal
        title={`文件预览：${previewFileName}`}
        open={previewVisible}
        onCancel={closePreview}
        footer={[
          <Button key="close" onClick={closePreview}>
            关闭
          </Button>,
        ]}
        width={previewFileType === "text" ? PREVIEW_MODAL_WIDTH.text : PREVIEW_MODAL_WIDTH.media}
      >
        {previewFileType === "text" && (
          <pre
            style={{
              maxHeight: `${PREVIEW_MAX_HEIGHT}px`,
              overflow: "auto",
              whiteSpace: "pre-wrap",
              wordBreak: "break-all",
              fontSize: PREVIEW_TEXT_FONT_SIZE,
              color: "#222",
              backgroundColor: "#f5f5f5",
              padding: `${PREVIEW_TEXT_PADDING}px`,
              borderRadius: "4px",
            }}
          >
            {previewContent}
          </pre>
        )}
        {previewFileType === "image" && (
          <div style={{ textAlign: "center" }}>
            <img
              src={previewMediaUrl}
              alt={previewFileName}
              style={{ maxWidth: "100%", maxHeight: `${PREVIEW_MAX_HEIGHT}px`, objectFit: "contain" }}
            />
          </div>
        )}
        {previewFileType === "pdf" && (
          <>
            {previewMediaUrl ? (
              <iframe
                src={previewMediaUrl}
                title={previewFileName || "PDF 预览"}
                style={{ width: "100%", height: `${PREVIEW_MAX_HEIGHT}px`, border: "none" }}
              />
            ) : (
              <div
                style={{
                  height: `${PREVIEW_MAX_HEIGHT}px`,
                  display: "flex",
                  flexDirection: "column",
                  alignItems: "center",
                  justifyContent: "center",
                  gap: 12,
                  color: "#666",
                }}
              >
                {officePreviewStatus === "FAILED" ? (
                  <>
                    <div>转换失败</div>
                    <div>{officePreviewError || "请稍后重试"}</div>
                  </>
                ) : (
                  <>
                    <Spin />
                    <div>正在转换，请稍候...</div>
                  </>
                )}
              </div>
            )}
          </>
        )}
        {previewFileType === "video" && (
          <div style={{ textAlign: "center" }}>
            <video
              src={previewMediaUrl}
              controls
              style={{ maxWidth: "100%", maxHeight: `${PREVIEW_MAX_HEIGHT}px` }}
            >
              您的浏览器不支持视频播放
            </video>
          </div>
        )}
        {previewFileType === "audio" && (
          <div style={{ textAlign: "center", padding: `${PREVIEW_AUDIO_PADDING}px 0` }}>
            <audio src={previewMediaUrl} controls style={{ width: "100%" }}>
              您的浏览器不支持音频播放
            </audio>
          </div>
        )}
      </Modal>

      <Modal
        open={readModalOpen}
        title={`阅读：${readTitle}`}
        width={820}
        onCancel={() => {
          setReadModalOpen(false);
          setReadContent("");
          setReadTitle("");
        }}
        footer={[
          <Button
            key="close"
            onClick={() => {
              setReadModalOpen(false);
              setReadContent("");
              setReadTitle("");
            }}
          >
            关闭
          </Button>,
        ]}
      >
        <pre
          className="max-h-[520px] overflow-auto rounded bg-gray-50 p-4 text-xs whitespace-pre-wrap break-all"
        >
          {readContent}
        </pre>
      </Modal>
    </div>
  );
};

export default KnowledgeSetDetail;
