import type React from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import {
  Table,
  Badge,
  Button,
  Breadcrumb,
  Tooltip,
  App,
  Card,
  Input,
  Empty,
  Spin,
} from "antd";
import {
  DeleteOutlined,
  EditOutlined,
  ReloadOutlined,
} from "@ant-design/icons";
import { useNavigate, useParams, useSearchParams } from "react-router";
import DetailHeader from "@/components/DetailHeader";
import { SearchControls } from "@/components/SearchControls";
import { KBFile, KnowledgeBaseItem } from "../knowledge-base.model";
import { mapFileData, mapKnowledgeBase } from "../knowledge-base.const";
import {
  deleteKnowledgeBaseByIdUsingDelete,
  deleteKnowledgeBaseFileByIdUsingDelete,
  queryKnowledgeBaseByIdUsingGet,
  queryKnowledgeBaseFilesUsingGet,
  retrieveKnowledgeBaseContent,
} from "../knowledge-base.api";
import AddDataDialog from "../components/AddDataDialog";
import CreateKnowledgeBase from "../components/CreateKnowledgeBase";
import { File, Folder } from "lucide-react";

interface StatisticItem {
  icon?: React.ReactNode;
  label: string;
  value: string | number;
}
interface RagChunk {
  id: string;
  text: string;
  metadata: string;
}
interface RecallResult {
  score: number;
  entity: RagChunk;
  id?: string | object;
  primaryKey?: string;
}

type KBFileRow = KBFile & {
  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 resolveFileRelativePath = (file: KBFile) => {
  const rawPath = file.relativePath || file.fileName || file.name || "";
  return normalizePath(rawPath).replace(/^\/+/, "");
};

const KnowledgeBaseDetailPage: React.FC = () => {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const { message } = App.useApp();
  const { id } = useParams<{ id: string }>();
  const [knowledgeBase, setKnowledgeBase] = useState<KnowledgeBaseItem | undefined>(undefined);
  const [showEdit, setShowEdit] = useState(false);
  const [activeTab, setActiveTab] = useState<'fileList' | 'recallTest'>('fileList');
  const [filePrefix, setFilePrefix] = useState("");
  const [fileKeyword, setFileKeyword] = useState("");
  const [filesLoading, setFilesLoading] = useState(false);
  const [allFiles, setAllFiles] = useState<KBFile[]>([]);
  const [filePagination, setFilePagination] = useState({
    current: 1,
    pageSize: 10,
  });
  const [recallLoading, setRecallLoading] = useState(false);
  const [recallResults, setRecallResults] = useState<RecallResult[]>([]);
  const [recallQuery, setRecallQuery] = useState("");

  const fetchKnowledgeBaseDetails = useCallback(async (baseId: string) => {
    const { data } = await queryKnowledgeBaseByIdUsingGet(baseId);
    setKnowledgeBase(mapKnowledgeBase(data));
  }, []);

  const fetchFiles = useCallback(async () => {
    if (!id) {
      setAllFiles([]);
      return;
    }
    setFilesLoading(true);
    try {
      const pageSize = 200;
      let page = 0;
      let combined: KBFile[] = [];
      const currentPrefix = normalizePrefix(filePrefix);
      const keyword = fileKeyword.trim();
      while (true) {
        const { data } = await queryKnowledgeBaseFilesUsingGet(id, {
          page,
          size: pageSize,
          ...(currentPrefix ? { relativePath: currentPrefix } : {}),
          ...(keyword ? { fileName: keyword } : {}),
        });
        const content = Array.isArray(data?.content) ? data.content : [];
        combined = combined.concat(content.map(mapFileData));
        if (content.length < pageSize) {
          break;
        }
        if (typeof data?.totalElements === "number" && combined.length >= data.totalElements) {
          break;
        }
        page += 1;
      }
      setAllFiles(combined);
    } catch (error) {
      console.error("Failed to fetch knowledge base files:", error);
      message.error("文件列表加载失败");
    } finally {
      setFilesLoading(false);
    }
  }, [id, filePrefix, fileKeyword, message]);

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

  useEffect(() => {
    if (!id) {
      return;
    }
    const prefixParam = searchParams.get("prefix");
    const fileNameParam = searchParams.get("fileName");
    setFilePrefix(prefixParam ? normalizePrefix(prefixParam) : "");
    setFileKeyword(fileNameParam ? fileNameParam : "");
  }, [id, searchParams]);

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

  // File table logic
  const handleDeleteFile = async (file: KBFileRow) => {
    try {
      await deleteKnowledgeBaseFileByIdUsingDelete(knowledgeBase!.id, {
        ids: [file.id]
      });
      message.success("文件已删除");
      fetchFiles();
    } catch {
      message.error("文件删除失败");
    }
  };

  const handleDeleteKB = async (kb: KnowledgeBaseItem) => {
    await deleteKnowledgeBaseByIdUsingDelete(kb.id);
    message.success("知识库已删除");
    navigate("/data/knowledge-base");
  };

  const handleRefreshPage = () => {
    if (knowledgeBase) {
      fetchKnowledgeBaseDetails(knowledgeBase.id);
    }
    fetchFiles();
    setShowEdit(false);
  };

  const handleRecallTest = async () => {
    if (!recallQuery || !knowledgeBase?.id) return;
    setRecallLoading(true);
    try {
      const result = await retrieveKnowledgeBaseContent({
        query: recallQuery,
        topK: 10,
        threshold: 0.2,
        knowledgeBaseIds: [knowledgeBase.id],
      });
      setRecallResults(result?.data || []);
    } catch {
      setRecallResults([]);
    }
    setRecallLoading(false);
  };

  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 handleDeleteDirectory = async (directoryName: string) => {
    if (!knowledgeBase?.id) {
      return;
    }
    const currentPrefix = normalizePrefix(filePrefix);
    const directoryPrefix = normalizePrefix(`${currentPrefix}${directoryName}`);
    const targetIds = allFiles
      .filter((file) => {
        const fullPath = resolveFileRelativePath(file);
        return fullPath.startsWith(directoryPrefix);
      })
      .map((file) => file.id);
    if (targetIds.length === 0) {
      message.info("该文件夹为空");
      return;
    }
    try {
      await deleteKnowledgeBaseFileByIdUsingDelete(knowledgeBase.id, {
        ids: targetIds,
      });
      message.success(`已删除 ${targetIds.length} 个文件`);
      fetchFiles();
    } catch {
      message.error("文件夹删除失败");
    }
  };

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

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

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

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

    allFiles.forEach((file) => {
      const fullPath = resolveFileRelativePath(file);
      if (!fullPath) {
        return;
      }
      const segments = splitRelativePath(fullPath, normalizedPrefix);
      if (segments.length === 0) {
        return;
      }
      const leafName = segments[0];

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

      const normalizedFileName = normalizePath(file.fileName);
      const displayName = normalizedFileName.includes(PATH_SEPARATOR)
        ? leafName
        : file.fileName || leafName;
      fileItems.push({
        ...file,
        name: displayName,
        displayName,
        fullPath,
      });
    });

    const folderItems: KBFileRow[] = Array.from(folderMap.values()).map(
      (entry) =>
        ({
          id: `directory-${normalizedPrefix}${entry.name}`,
          fileName: entry.name,
          name: entry.name,
          status: null,
          chunkCount: 0,
          createdAt: "",
          updatedAt: "",
          metadata: {},
          knowledgeBaseId: knowledgeBase?.id || "",
          fileId: "",
          updatedBy: "",
          createdBy: "",
          isDirectory: true,
          displayName: entry.name,
          fullPath: `${normalizedPrefix}${entry.name}/`,
          fileCount: entry.fileCount,
        }) as KBFileRow
    );

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

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

    const combined = [...folderItems, ...fileItems];
    return { rows: combined, total: combined.length };
  }, [allFiles, knowledgeBase?.id, normalizedPrefix]);

  const filePageCurrent = filePagination.current;
  const filePageSize = filePagination.pageSize;

  const pagedFileRows = useMemo(() => {
    const startIndex = (filePageCurrent - 1) * filePageSize;
    const endIndex = startIndex + filePageSize;
    return fileRows.slice(startIndex, endIndex);
  }, [filePageCurrent, filePageSize, fileRows]);

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

  const operations = [
    {
      key: "edit",
      label: "编辑知识库",
      icon: <EditOutlined className="w-4 h-4" />,
      onClick: () => {
        setShowEdit(true);
      },
    },
    {
      key: "refresh",
      label: "刷新知识库",
      icon: <ReloadOutlined className="w-4 h-4" />,
      onClick: () => {
        handleRefreshPage();
      },
    },
    {
      key: "delete",
      label: "删除知识库",
      danger: true,
      confirm: {
        title: "确认删除该知识库吗？",
        description: "删除后将无法恢复，请谨慎操作。",
        cancelText: "取消",
        okText: "删除",
        okType: "danger",
        onConfirm: () => knowledgeBase && handleDeleteKB(knowledgeBase),
      },
      icon: <DeleteOutlined className="w-4 h-4" />,
    },
  ];

  const fileOps = [
    {
      key: "delete",
      label: "删除文件",
      icon: <DeleteOutlined className="w-4 h-4" />,
      danger: true,
      onClick: handleDeleteFile,
    },
  ];

  const fileColumns = [
    {
      title: "文件名",
      dataIndex: "name",
      key: "name",
      width: 200,
      ellipsis: true,
      fixed: "left" as const,
      render: (name: string, record: KBFileRow) => {
        const displayName = record.displayName || name;
        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: "status",
      key: "vectorizationStatus",
      width: 120,
      render: (status: unknown, record: KBFileRow) => {
        if (record.isDirectory) {
          return <Badge color="default" text="文件夹" />;
        }
        if (typeof status === "object" && status !== null) {
          const s = status as { color?: string; label?: string };
          return <Badge color={s.color} text={s.label} />;
        }
        return <Badge color="default" text={String(status)} />;
      },
    },
    {
      title: "分块数",
      dataIndex: "chunkCount",
      key: "chunkCount",
      width: 100,
      ellipsis: true,
      render: (value: number, record: KBFileRow) =>
        record.isDirectory ? "-" : value ?? 0,
    },
    {
      title: "创建时间",
      dataIndex: "createdAt",
      key: "createdAt",
      ellipsis: true,
      width: 180,
      render: (value: string, record: KBFileRow) =>
        record.isDirectory ? "-" : value || "-",
    },
    {
      title: "更新时间",
      dataIndex: "updatedAt",
      key: "updatedAt",
      ellipsis: true,
      width: 180,
      render: (value: string, record: KBFileRow) =>
        record.isDirectory ? "-" : value || "-",
    },
    {
      title: "操作",
      key: "actions",
      align: "right" as const,
      width: 100,
      render: (_: unknown, file: KBFileRow) => {
        if (file.isDirectory) {
          return (
            <Tooltip title="删除文件夹">
              <Button
                type="text"
                icon={<DeleteOutlined className="w-4 h-4" />}
                danger
                onClick={() => {
                  modal.confirm({
                    title: "确认删除该文件夹吗？",
                    content: `删除后将移除文件夹 “${file.displayName || file.name}” 下的全部文件，且无法恢复。`,
                    okText: "删除",
                    okType: "danger",
                    cancelText: "取消",
                    onOk: () => handleDeleteDirectory(file.displayName || file.name),
                  });
                }}
              />
            </Tooltip>
          );
        }
        return (
          <div>
            {fileOps.map((op) => (
              <Tooltip key={op.key} title={op.label}>
                <Button
                  type="text"
                  icon={op.icon}
                  danger={op?.danger}
                  onClick={() => op.onClick(file)}
                />
              </Tooltip>
            ))}
          </div>
        );
      },
    },
  ];

  return (
    <div className="h-full flex flex-col">
      <div className="mb-4">
        <Breadcrumb>
          <Breadcrumb.Item>
            <a onClick={() => navigate("/data/knowledge-base")}>知识库</a>
          </Breadcrumb.Item>
          <Breadcrumb.Item>{knowledgeBase?.name}</Breadcrumb.Item>
        </Breadcrumb>
      </div>
      <DetailHeader
        data={knowledgeBase}
        statistics={knowledgeBase && Array.isArray((knowledgeBase as { statistics?: StatisticItem[] }).statistics)
          ? ((knowledgeBase as { statistics?: StatisticItem[] }).statistics ?? [])
          : []}
        operations={operations}
      />
      <CreateKnowledgeBase
        showBtn={false}
        isEdit={showEdit}
        data={knowledgeBase}
        onUpdate={handleRefreshPage}
        onClose={() => setShowEdit(false)}
      />
      <div className="flex-1 border-card p-6 mt-4">
        <div className="flex items-center justify-between mb-4 gap-3">
          <div className="flex items-center gap-2">
            <Button type={activeTab === 'fileList' ? 'primary' : 'default'} onClick={() => setActiveTab('fileList')}>
              文件列表
            </Button>
            <Button type={activeTab === 'recallTest' ? 'primary' : 'default'} onClick={() => setActiveTab('recallTest')}>
              召回测试
            </Button>
          </div>
          {activeTab === 'fileList' && (
            <>
              <div className="flex-1">
                <SearchControls
                  searchTerm={fileKeyword}
                  onSearchChange={handleKeywordChange}
                  searchPlaceholder="搜索文件名..."
                  filters={[]}
                  onFiltersChange={() => {}}
                  onClearFilters={() => setFileKeyword("")}
                  showViewToggle={false}
                  showReload={false}
                />
              </div>
              <AddDataDialog knowledgeBase={knowledgeBase} onDataAdded={handleRefreshPage} />
            </>
          )}
        </div>

        {activeTab === 'fileList' ? (
          <>
            <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>
            <Table
              loading={filesLoading}
              columns={fileColumns}
              dataSource={pagedFileRows}
              rowKey="id"
              pagination={{
                current: filePagination.current,
                pageSize: filePagination.pageSize,
                total: fileTotal,
                showTotal: (total) => `共 ${total} 条`,
                onChange: (page, pageSize) =>
                  setFilePagination({
                    current: page,
                    pageSize: pageSize || filePagination.pageSize,
                  }),
              }}
              scroll={{ y: "calc(100vh - 30rem)" }}
            />
          </>
        ) : (
          <div className="p-2">
            <div style={{ fontSize: 14, fontWeight: 300, marginBottom: 8 }}>基于语义文本检索和全文检索后的加权平均结果</div>
            <div className="flex items-center mb-4">
              <Input.Search
                value={recallQuery}
                onChange={e => setRecallQuery(e.target.value)}
                onSearch={handleRecallTest}
                placeholder="请输入召回测试问题"
                enterButton="检索"
                loading={recallLoading}
                style={{ width: "100%", fontSize: 18, height: 48 }}
              />
            </div>
            {recallLoading ? (
              <Spin className="mt-8" />
            ) : recallResults.length === 0 ? (
              <Empty description="暂无召回结果" />
            ) : (
              <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                {recallResults.map((item, idx) => (
                  <Card key={idx} title={`得分：${item.score?.toFixed(4) ?? "-"}`}
                    extra={<span style={{ fontSize: 12 }}>ID: {item.entity?.id ?? "-"}</span>}
                    style={{ wordBreak: "break-all" }}
                  >
                    <div style={{ marginBottom: 8, fontWeight: 500 }}>{item.entity?.text ?? ""}</div>
                    <div style={{ fontSize: 12, color: '#888' }}>
                      metadata: <pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all', margin: 0 }}>{item.entity?.metadata}</pre>
                    </div>
                  </Card>
                ))}
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
};

export default KnowledgeBaseDetailPage;
