import { PlusOutlined, UploadOutlined, VideoCameraAddOutlined } from "@ant-design/icons";
import { Upload as AntUpload, Button, message, Modal } from "antd";
import { 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("");

  // 预设的文件格式
  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 0;
  };
  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 = ({ file, fileList }) => {
    const acceptList = accept ? accept.split(",") : [];
    const ratioArr = ratio ? ratio.split("*") : [];
    const suffix = file.name.substring(
      file.name.lastIndexOf("."),
      file.name.length,
    );
    const maxSize = size * 1024 * 1024;

    // 验证文件格式
    if (acceptList.length > 0 && !acceptList.includes(suffix)) {
      message.warning(`只能上传${acceptTip}格式的文件`);
      return;
    }

    // 验证文件大小
    if (maxSize && file.size > maxSize) {
      message.warning(`文件大小不能超过${size}M`);
      return;
    }

    // 验证图片分辨率
    if (ratioArr.length === 2 && file.type?.startsWith("image/")) {
      const validateImageResolution = (imageUrl) => {
        const img = new Image();
        img.onload = () => {
          if (img.width !== +ratioArr[0] || img.height !== +ratioArr[1]) {
            message.warning(`只能上传${ratio}分辨率的图片`);
            const filtered = fileList.filter(item => item.uid !== file.uid);
            onChange?.(filtered);
            return;
          }
          onChange?.(fileList);
        };
        img.src = imageUrl;
      };

      // 如果有现成的URL则直接使用，否则使用FileReader读取本地文件
      if (file.url) {
        validateImageResolution(file.url);
      }
      else {
        const reader = new FileReader();
        reader.onload = (e) => {
          validateImageResolution(e.target.result);
        };
        reader.readAsDataURL(file);
      }
    }
    else {
      onChange?.(fileList);
    }
  };

  // 删除文件
  const handleRemove = (file) => {
    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;
