import { PlusOutlined, UploadOutlined, VideoCameraAddOutlined } from "@ant-design/icons";
import { Upload as AntUpload, Button, message, Modal } from "antd";
import { useRef, useState } from "react";

/**
 * 文件上传组件
 */
const Upload = (props) => {
  const {
    value = [],
    onChange,
    onPreview,
    onRemove,
    onGetRemoveFile,
    beforeUpload,
    maxCount: externalMaxCount,
    listType: externalListType,
    accept: externalAccept,
    ratio = "",
    showTip = true,
    multiple = true,
    size: externalSize,
    tipContent,
    uploadButtonText: externalUploadButtonText,
    fileType: externalFileType,
    ...restProps
  } = props;

  const [previewVisible, setPreviewVisible] = useState(false);
  const [previewImage, setPreviewImage] = useState("");

  // 记录已经提示过错误的文件uid，避免重复提示
  const warnedFileUids = useRef(new Set());

  // 预设的文件格式
  const imageAccept = ".jpg,.jpeg,.png";
  const documentAccept = ".pdf,.doc,.docx";
  const videoAccept = ".mp4";

  // 根据accept自动判断文件类型
  const getAutoFileType = () => {
    if (externalAccept) {
      if (externalAccept === "*")
        return "document";
      const acceptList = externalAccept.split(",");
      if (acceptList.some(format => videoAccept.split(",").includes(format)))
        return "video";
      if (acceptList.some(format => documentAccept.split(",").includes(format)))
        return "document";
      if (acceptList.some(format => imageAccept.split(",").includes(format)))
        return "image";
      return "document";
    }
    return "image";
  };
  const fileType = externalFileType || getAutoFileType();

  // 文件类型判断
  const isImageType = fileType === "image";
  const isVideoType = fileType === "video";
  const isDocumentType = fileType === "document";

  // 获取listType
  const getListType = () => {
    if (externalListType)
      return externalListType;
    if (externalAccept === "*")
      return "text";
    if (fileType === "image")
      return "picture-card";
    return "text";
  };
  const listType = getListType();

  // 获取文件格式
  const getAccept = () => {
    if (externalAccept)
      return externalAccept === "*" ? "" : externalAccept;
    if (isImageType)
      return imageAccept;
    if (isVideoType)
      return videoAccept;
    if (isDocumentType)
      return documentAccept;
    return imageAccept;
  };
  const accept = getAccept();

  // 获取默认上传数量
  const getMaxCount = () => {
    if (externalMaxCount)
      return externalMaxCount;
    if (isVideoType)
      return 1;
    if (isImageType)
      return 4;
    if (isDocumentType)
      return 4;
    return 1;
  };
  const maxCount = getMaxCount();

  // 获取默认文件大小
  const getSize = () => {
    if (externalSize)
      return externalSize;
    if (isVideoType)
      return 100;
    return 10;
  };
  const size = getSize();

  // 上传按钮文字
  const uploadButtonText = externalUploadButtonText || (isVideoType ? "上传视频" : "上传附件");

  // 文件格式提示
  const acceptTip = accept.replace(/\./g, "").split(",").join("、");

  // 生成提示信息
  const getTipText = () => {
    if (tipContent)
      return tipContent;

    const tips = [
      `最多上传${maxCount}个文件`,
      accept
        ? `并且只能上传${acceptTip}格式的文件`
        : "可以上传任意格式的文件",
      size ? `文件大小不能超过${size}M` : "",
      ratio ? `只能上传${ratio}分辨率的图片` : "",
    ].filter(Boolean);

    return `${tips.join("，")}。`;
  };

  const handleBeforeUpload = (file, fileList) => {
    if (beforeUpload)
      return beforeUpload(file, fileList);
    return false;
  };

  // 文件状态改变
  const handleChange = ({ fileList }) => {
    const acceptList = accept ? accept.split(",") : [];
    const ratioArr = ratio ? ratio.split("*") : [];
    const maxSize = size * 1024 * 1024;

    // 获取新增的文件（只验证新文件，不重复验证已存在的文件）
    const existingUids = new Set(value.map(f => f.uid));
    const newFiles = fileList.filter(file => !existingUids.has(file.uid));

    // 如果没有新文件，直接更新
    if (newFiles.length === 0) {
      onChange?.(fileList);
      return;
    }

    // 验证文件格式
    const validateFileFormat = (fileItem) => {
      const suffix = fileItem.name?.substring(
        fileItem.name.lastIndexOf("."),
        fileItem.name.length,
      ) || "";

      if (acceptList.length > 0 && !acceptList.includes(suffix)) {
        // 只提示未提示过的文件
        if (!warnedFileUids.current.has(fileItem.uid)) {
          warnedFileUids.current.add(fileItem.uid);
          message.warning(`${fileItem.name}：只能上传${acceptTip}格式的文件`);
        }
        return false;
      }
      return true;
    };

    // 验证文件大小
    const validateFileSize = (fileItem) => {
      if (maxSize && fileItem.size > maxSize) {
        // 只提示未提示过的文件
        if (!warnedFileUids.current.has(fileItem.uid)) {
          warnedFileUids.current.add(fileItem.uid);
          message.warning(`${fileItem.name}：文件大小不能超过${size}M`);
        }
        return false;
      }
      return true;
    };

    // 验证图片分辨率
    const validateImageResolution = (fileItem) => {
      return new Promise((resolve) => {
        if (ratioArr.length !== 2 || !fileItem.type?.startsWith("image/")) {
          resolve(true);
          return;
        }

        const checkResolution = (imageUrl) => {
          return new Promise((resolveInner) => {
            const img = new Image();
            img.onload = () => {
              const isValid = img.width === +ratioArr[0] && img.height === +ratioArr[1];
              if (!isValid) {
                // 只提示未提示过的文件
                if (!warnedFileUids.current.has(fileItem.uid)) {
                  warnedFileUids.current.add(fileItem.uid);
                  message.warning(`${fileItem.name}：只能上传${ratio}分辨率的图片`);
                }
              }
              resolveInner(isValid);
            };
            img.onerror = () => resolveInner(false);
            img.src = imageUrl;
          });
        };

        if (fileItem.url) {
          checkResolution(fileItem.url).then(resolve);
        }
        else {
          const reader = new FileReader();
          reader.onload = (e) => {
            checkResolution(e.target.result).then(resolve);
          };
          reader.onerror = () => resolve(false);
          reader.readAsDataURL(fileItem.originFileObj);
        }
      });
    };

    // 只验证新增的文件
    const validateNewFiles = async (files) => {
      const validFiles = [];
      const invalidFiles = [];

      for (const fileItem of files) {
        // 验证文件格式
        if (!validateFileFormat(fileItem)) {
          invalidFiles.push(fileItem);
          continue;
        }

        // 验证文件大小
        if (!validateFileSize(fileItem)) {
          invalidFiles.push(fileItem);
          continue;
        }

        // 验证图片分辨率（异步）
        const isValidResolution = await validateImageResolution(fileItem);
        if (!isValidResolution) {
          invalidFiles.push(fileItem);
          continue;
        }

        validFiles.push(fileItem);
      }

      return { validFiles, invalidFiles };
    };

    // 执行验证并更新
    validateNewFiles(newFiles).then(({ validFiles: validNewFiles }) => {
      // 合并已存在的文件和通过验证的新文件
      const finalFileList = [
        ...value, // 已存在的文件
        ...validNewFiles, // 通过验证的新文件
      ];
      onChange?.(finalFileList);
    });
  };

  // 删除文件
  const handleRemove = (file) => {
    // 清理该文件的提示记录
    warnedFileUids.current.delete(file.uid);
    if (!file.originFileObj)
      onGetRemoveFile?.(file);
    return onRemove?.(file);
  };

  // 预览文件
  const handlePreview = (file) => {
    if (isImageType) {
      setPreviewImage(file.url || file.thumbUrl);
      setPreviewVisible(true);
    }
    onPreview?.(file);
  };

  // 关闭预览
  const handleCancel = () => {
    setPreviewVisible(false);
  };

  // 上传按钮
  const uploadButton
    = isImageType
      ? (
          <div>
            <PlusOutlined style={{ fontSize: 32 }} />
          </div>
        )
      : (
          <Button
            type="primary"
            icon={isVideoType ? <VideoCameraAddOutlined /> : <UploadOutlined />}
          >
            {uploadButtonText}
          </Button>
        );

  return (
    <>
      <AntUpload
        fileList={value}
        multiple={multiple}
        maxCount={maxCount}
        listType={listType}
        accept={accept}
        onChange={handleChange}
        onPreview={handlePreview}
        onRemove={handleRemove}
        beforeUpload={handleBeforeUpload}
        {...restProps}
      >
        {value.length >= maxCount ? null : uploadButton}
      </AntUpload>
      {
        showTip
          ? (getTipText()) && (
              <div style={{ marginTop: 10, color: "#ff4d4f" }}>
                {getTipText()}
              </div>
            )
          : null
      }
      <Modal
        open={previewVisible}
        title="查看图片"
        footer={null}
        onCancel={handleCancel}
      >
        <img
          alt="preview"
          style={{ width: "100%", objectFit: "scale-down" }}
          src={previewImage}
        />
      </Modal>
    </>
  );
};

Upload.displayName = "Upload";

export default Upload;
