import * as React from 'react';
import {
  Upload,
  Button,
  Icon,
  message,
  ErrorTip,
  ImagePreview,
  ConfigProvider,
} from 'tea-component';
import { v4 } from 'uuid';
import classNames from '../../../utils/classnames';
import { getCloudInstance, getTempFileURL } from '../../../utils/tcb';
import { isCloudFileID } from '../../../utils/platform';
import isObjectEqual from '../../../utils/isObjectEqual';
import * as PropTypes from 'prop-types';

// 默认组件类前缀
export const CLASS_PREFIX = 'weda-uploader-pc';
// 默认图片类型
const IMAGE_TYPES = [
  'image/jpg',
  'image/png',
  'image/tif',
  'image/bmp',
  'image/jpeg',
  'image/tiff',
];

/**
 * 上传图片-官方组件
 */
// eslint-disable-next-line react/prop-types
export function UploaderPC({layout, className, id, style,title,tips, ...props }) {
  const cls = classNames({
    'weda-ui': true,
    [CLASS_PREFIX]: true,
    [layout]: layout,
    [className]: className,
  });
  return (
    <div className={cls} id={id} style={style}>
        <div className={`${CLASS_PREFIX}__header`}>
          {title && <div className={`${CLASS_PREFIX}__title`}>{title}</div>}
          {tips && (
            <div className={`${CLASS_PREFIX}__description`}>{tips || ''}</div>
          )}
        </div>
        <UploaderPCInner {...props} />
    </div>
);
}


export function UploaderPCInner(props) {
  let {
    tips = '',
    btnTitle = '上传图片',
    maxUploadCount = 9,
    maxSize = 10,
    value, // 需要兼容 cloud:和https: 协议，需要兼容 字符串和字符串数组
    acceptTypes = IMAGE_TYPES,
    uploadPath = 'weda-uploader',
    uploadFileName = 'image',
    events = {},
    single = false,
    onChange,
  } = props;


  let initialValue = []
    .concat(value)
    .filter((d) => typeof d === 'string' && d !== '');
  if (single) {
    maxUploadCount = 1;
    initialValue = initialValue[0] ? [initialValue[0]] : [];
  }

  // 上传中
  const [uploading, setUploading] = React.useState(false);
  //上传进度
  const [progress, setProgress] = React.useState(0);
  // 文件列表
  const [fileIDList, setfileIDList] = React.useState(initialValue);
  const fileRef = React.useRef(fileIDList);

  // 值变化事件
  React.useEffect(() => {
    if (!isObjectEqual(fileRef.current, fileIDList)) {
      events.change && events.change({ value: fileIDList });
      if (single) {
        const file = fileIDList[0] || '';
        file && onChange && onChange(file);
      } else {
        onChange && onChange(fileIDList);
      }
      fileRef.current = fileIDList;
    }
  });

  // 方法：上传前，判断图片大小、数量是否满足，取消默认组件的上传事件，用自定义的 tcb 上传方法
  const beforeHandle = (file, fileList, isAccepted, error) => {
    if (!isAccepted) {
      try {
        const errorList = [];
        if (error.find((item) => item?.code === 'file-invalid-type')) {
          errorList.push('上传图片类型错误');
        }
        if (error.find((item) => item?.code === 'file-too-large')) {
          errorList.push(`上传图片大小不能超过${maxSize}M`);
        }
        message.error({ content: errorList.join(', ') });
      } catch (e) {}
      return false;
    }
    uploadTcb(file);
    return false;
  };

  // 自定义上传到 Tcb 的 COS
  const uploadTcb = (file) => {
    setUploading(true);
    getCloudInstance().then(async (tcb) => {
      try {
        const fileType = file.type.split('/')?.[1];
        const cloudPath = `${uploadPath}/${uploadFileName}-${v4()}.${fileType}`;
        const { fileID } = await tcb.uploadFile({
          cloudPath,
          filePath: file,
          onUploadProgress: onProgress,
        });
        fileID && setfileIDList((list) => [...list, fileID]);
        fileID && events.success && events.success({ value: fileID, file });
      } catch (e) {
        events.error && events.error({ value: e, file });
      } finally {
        setUploading(false);
        setProgress(0);
      }
    });
  };

  // 计算上传进度
  const onProgress = (progressEvent) => {
    let percentCompleted = 0;
    try {
      percentCompleted = Math.round(
        (progressEvent.loaded * 100) / progressEvent.total
      );
      percentCompleted < 100 ? percentCompleted : 100;
    } catch (e) {}
    setProgress(percentCompleted);
  };

  // 删除图片
  const deleteHandle = (fileID) => {
    setfileIDList((list) => list.filter((d) => d !== fileID));
  };
  
  // 转换后的属性
  const extraProps = {};
  extraProps['accept'] =
    acceptTypes.includes('image/*') || acceptTypes.length === 0
      ? IMAGE_TYPES
      : Array.from(new Set(acceptTypes));
  tips && (extraProps['title'] = tips);
  maxSize && (extraProps['maxSize'] = maxSize * 1024 * 1024);

  return (
    <ConfigProvider classPrefix="wedatea2td">
        <div className="_weda-fn-upload-result">
          {fileIDList.map((d) => (
            <div className="_weda-fn-upload-result__item" key={d}>
              <TcbImage fileID={d} />
              <div className="_weda-fn-upload-result__op">
                <Button
                  onClick={() => deleteHandle(d)}
                  className={`${CLASS_PREFIX}__btn`}
                  >
                  删除
                </Button>
              </div>
            </div>
          ))}
          {uploading && (
            <div className="_weda-fn-upload-result__item">
              <div className="_weda-fn-upload-result__status" key="_place_image">
                <Icon type="loading" />
                {!!progress && <span className="wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset">上传{progress}%...</span>}
              </div>
            </div>
          )}
          <div className={`${CLASS_PREFIX}__input-box`}>
          {fileIDList.length < maxUploadCount &&
          <Upload {...extraProps} beforeUpload={beforeHandle}>
              <li className="_weda-fn-upload-result__item _weda-fn-upload-result__item--upload">
              <div className="_weda-fn-upload-result__status">
                <i className="wedatea2td-icon wedatea2td-icon-plus" role="img" aria-label="plus"></i>
                <span className="wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset">{btnTitle}</span>
              </div>
            </li>
          </Upload>
          }
        </div>
        </div>
        
    </ConfigProvider>
  );
}

/**
 * 单张图片回显组件
 */
export const TcbImage = (props) => {
  const { fileID, isZoom, ...rest } = props;
  const [src, setSrc] = React.useState('');
  const [isError, setIsError] = React.useState(false);
  React.useEffect(() => {
    const getSrc = async () => {
      try {
        const _src = await getTempFileURL(fileID);
        _src ? setSrc(_src) : setIsError(true);
      } catch (e) {
        message.error('图片加载失败');
      }
    };
    isCloudFileID(fileID) ? getSrc() : setSrc(fileID);
  }, [fileID]);

  return isError ? (
    <ErrorTip />
  ) : src ? (
    isZoom ? (
      <ImagePreview
        key={fileID}
        className={`${CLASS_PREFIX}__image`}
        {...rest}
        src={src}
        previewSrc={src}
        onError={(e) => {
          setIsError(true);
          props?.onError && props.onError(e);
        }}
      />
    ) : (
      <img
        key={fileID}
        className={`${CLASS_PREFIX}__image`}
        // eslint-disable-next-line react/jsx-props-no-spreading
        {...rest}
        src={src}
        onError={(e) => {
          setIsError(true);
          props?.onError && props.onError(e);
        }}
      />
    )
  ) : null;
};

UploaderPCInner.propTypes = {
  className: PropTypes.string, // 传入类
  title: PropTypes.string, // 官方属性：标题
  tips: PropTypes.string, // 官方属性：提示
  btnTitle: PropTypes.string, // 官方属性：上传按钮标题
  maxUploadCount: PropTypes.number, // 官方属性：上传图片最大数量
  maxSize: PropTypes.number, // 官方属性：单个图片大小限制，单位是M
  acceptTypes: PropTypes.array, // 官方属性：图片类型，TIF | BMP | JPEG | TIFF | PNG
  uploadPath: PropTypes.string, // 上传路径
  uploadFileName: PropTypes.string, // 上传文件名称
  single: PropTypes.bool, // 单张上传还是多张上传，对应 onChange 参数为字符串还是字符串数组，value 在处理过程统一转为字符串数组
  events: PropTypes.objectOf(PropTypes.func), // 事件
  value: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), // 初始值，该参数需配合 formily 使用
  onChange: PropTypes.objectOf(PropTypes.func), // 值变化，该参数需配合 formily 使用
  style: PropTypes.object,
  id: PropTypes.string,
  layout: PropTypes.oneOf(['horizontal', 'vertical']),
  disabled: PropTypes.bool
};

TcbImage.propTypes = {
  fileID: PropTypes.string, // 云存储id
  isZoom: PropTypes.bool, // 是否点击放大
  onError: PropTypes.func, // 图片显示错误事件
};