import React from 'react';
import { Modal } from 'antd';
import OSS from 'ali-oss';
import Service from '@/common/js/service';
import { getEllipsText } from "@/core/util";

import { DEFAULT_SIZE_UNIT, FileTypeIcon, FileVerifyMap } from "@/common/constants/academic/lessonEnum";
import { getFileTypeByName } from '../components/FolderManage';
import User from '@/common/js/user';
import './UploadProgressModal.less';

const UPLOAD_REGION = 'oss-cn-hangzhou';
const UPLOAD_PART_SIZE = 1024 * 1024; // 每个分片大小(byte)
const UPLOAD_PARALLEL = 5; // 同时上传的分片数

class UploadProgressModal extends React.Component {
  constructor(props)  {
    super(props);
    this.state = {
      fileList: [],
      showFileList: true,    // 默认展开上传进度
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.isOpen && !_.isEqual(nextProps.fileList, this.props.fileList)) {
      const { fileList } = nextProps;
      const _fileList = fileList.map((file) => {
        return {
          fileContent: file,
          status: 'waiting',
          checkpoints: {},
        }
      });

      const allFileList = [...this.state.fileList, ..._fileList];
      this.setState({
        fileList: allFileList
      }, () => {
        // 构建上传表单
        this.handleConstructForm(_fileList);
      })
    }
  }

  // 遍历上传文件，给每个文件构建上传表单
  handleConstructForm = (newFileList) => {
    const { fileList } = this.state;
    const length = fileList.length;
    const newLength = newFileList.length;
    const startI = length === newLength ? 0 : length - newLength;

    // 只给新添加的文件构建上传表单
    for (let i = startI; i < length; i++) {
      this.handleStartUpload(i);
    }
  }

  // 初始化ossClient
  initOssClient = (id, resourceName) => {
    const instId  = User.getStoreId();

    return new Promise(resolve => {
      Service.postJSON('mfs/anon/mfs/multiPartUpload', {
        instId,
        resourceName,
        data: { folderId: id  },
        accessTypeEnum: 'PUBLIC',
        bizCode: 'UPLOAD_FOLDER',
      }).then((res) => {
        const { result = {} } = res;
        const {
          bucket,
          callBack,
          resourceId,
          accessKeyId,
          securityToken,
          accessKeySecret,
          callbackBody,
          ossUri
        } = result;
        
        const ossClient = new OSS({
          bucket,
          accessKeyId,
          accessKeySecret,
          region: UPLOAD_REGION,
          stsToken: securityToken,
        });
        this.setState({
          ossClient,
          resourceId,
          callBack,
          callbackBody,
          ossUri
        });
        resolve({ ossClient, resourceId, callBack, callbackBody, ossUri });
      })
    })
  }

  handleStartUpload = (index) => {
    const { currentFolder } = this.props;
    const { fileList } = this.state;
    const file = fileList[index];
    const { fileContent } = file;
    const { id = 0 } = currentFolder;

    const { name, type } = fileContent;
    const resourceName = window.random_string(16) + name.slice(name.lastIndexOf('.'));

    const { instId } = window.currentUserInstInfo;
    // 开始上传之前初始化OssClient
    this.initOssClient(id, resourceName).then((result) => {
      const { ossClient, resourceId, callBack, callbackBody, ossUri } = result;
      ossClient.multipartUpload(ossUri, fileContent, {
        callback: {
          url: callBack,
          body: callbackBody,
          contentType: 'application/json',
        },
        parallel: UPLOAD_PARALLEL,
        partSize: UPLOAD_PART_SIZE,
        progress: (progress, checkpoint) => {
          this.onMultipartUploadProgress(progress, checkpoint, file)
        },
        mime: type
      }).then(url => {
        file.status = 'success';
        this.setState({ fileList });
        this.props.onUpload(fileContent, resourceId);
      }).catch(err => {
        file.status = 'fail';
        this.setState({ fileList });
      });
    });
  }

  // 给每个文件设置进度显示
  onMultipartUploadProgress = (progress = 0, checkpoint, file) => {
    const { fileList } = this.state;
    file.status = 'uploading';
    this.setState({ fileList })
    file.progress = (progress * 100).toFixed(2);
    
    // 如果文件小于100KB，不用记录断点，直接上传
    const { fileContent } = file;
    const { size } = fileContent;
    if (size > 100 * 1024) {
      file.checkpoints[checkpoint.uploadId] = checkpoint;
    }
    
  }

  // 断点续传
  handleReUpload = (index) => {
    const { fileList, ossClient, resourceId, callBack, callbackBody } = this.state;
    const currentFile = fileList[index];
    const { checkpoints, fileContent } = currentFile

    Object.values(checkpoints).forEach(checkpoint => {
      const { uploadId, file } = checkpoint;
      ossClient.multipartUpload(uploadId, file, {
        callback: {
          url: callBack,
          body: callbackBody,
          contentType: 'application/json',
        },
        checkpoint,
        parallel: UPLOAD_PARALLEL,
        partSize: UPLOAD_PART_SIZE,
        progress: (progress, checkpoint) => {
          this.onMultipartUploadProgress(progress, checkpoint, currentFile)
        },
        mime: file.type
      }).then(url => {
        currentFile.status = 'success';
        this.setState({ fileList });
        this.props.onUpload(fileContent, resourceId);
      }).catch(err => {
        currentFile.status = 'fail';
        this.setState({ fileList });
      });
    })
  }

  // 显示/隐藏上传进度
  handleToggleFileList = () => {
    this.setState({
      showFileList: !this.state.showFileList
    });
  }

  // 取消上传
  handleCancelAllUpload = () => {
    // 判断是否有正在上传或者待上传的文件，有的话弹出二次提示框
    const { fileList, ossClient } = this.state;
    const uploadingFileList = fileList.filter(file => file.status === 'uploading' || file.status === 'waiting');
    if (uploadingFileList.length) {
      Modal.confirm({
        title: '放弃上传',
        content: '上传列表中有未上传完成的文件，确定要放弃上传吗？',
        icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
        onOk: () => {
          uploadingFileList.forEach((uploadingFile, index) => {
            const { checkpoints } = uploadingFile;
            Object.values(checkpoints).forEach(checkpoint => {
              const { uploadId, name } = checkpoint;
              ossClient.abortMultipartUpload(name, uploadId);
            });
            fileList.splice(index, 1);
          })
          
          this.setState({ fileList });
          this.props.onCancel();
        }
      })
      return;
    }
    this.setState({ fileList: [] });
    this.props.onCancel();
  }

  // 取消单个文件上传
  handleCancelUpload = (currentFile, index) => {
    const { fileList, ossClient } = this.state;
    const { checkpoints } = currentFile;
    Object.values(checkpoints).forEach(checkpoint => {
      const { uploadId, name } = checkpoint;
      ossClient.abortMultipartUpload(name, uploadId);
    });

    fileList.splice(index, 1);
    this.setState({ fileList });

    if (!fileList.length) {
      this.props.onCancel();
    }
  }

  renderOverallProgress = () => {
    // 至少有一个文件正在上传，显示正在上传 N 项
    // 文件全都上传成功，显示为“N 项上传成功”
    // 文件全都上传失败，显示为“N 项上传失败
    // 文件部分上传成功、部分上传失败，显示为“M 项上传成功，N 项上传失败”
    const { fileList } = this.state;
    const allFileLength = fileList.length;
    const successFileLength = fileList.filter(file => file.status === 'success').length;
    const failFileLength = fileList.filter(file => file.status === 'fail').length;
    const uploadingFileLength = fileList.filter(file => file.status === 'uploading' || file.status === 'waiting').length;
    if (!!uploadingFileLength) {
      return (
        <span>正在上传{uploadingFileLength}项</span>
      )
    }

    if (successFileLength === allFileLength ) {
      return (
        <span>{successFileLength}项上传完成</span>
      )
    }
    if (failFileLength === allFileLength) {
      return (
        <span>{failFileLength}项上传失败</span>
      )
    }

    return (
      <span>{successFileLength}项上传完成，{failFileLength}项上传失败</span>
    )
  }

  render()  {
    const { fileList, showFileList } = this.state;
    const { isOpen } = this.props;  
    return (
      <div className={`prepare-lesson-upload-progress-modal ${isOpen ? 'visibile' : 'hidden'}`}>
        <div className={`modal-header ${showFileList ? 'no-radius' : ''}`}>
          {/* 总体进度 */}
          <div className="over-all-progress">
            { this.renderOverallProgress() }
          </div>

          <div className="operate">
            {
              showFileList ?
              <span
                className="icon iconfont"
                onClick={this.handleToggleFileList}
              >&#xe660;</span> :
              <span
                className="icon iconfont"
                style={{ transform: 'rotate(180deg)'}}
                onClick={this.handleToggleFileList}
              >&#xe660;</span>
            }
            <span
              className="icon iconfont"
              onClick={this.handleCancelAllUpload}
            >&#xe6ef;</span>
          </div>
        </div>
        {
          showFileList &&
          <div className="modal-body" style={{height:`${fileList.length * 53}px`}}>
            {
              fileList.map((file, index) => {
                let { size, type, name } = file.fileContent;
                let _size = `${(size / DEFAULT_SIZE_UNIT).toFixed(1)}M`;
                if (size < 0.1 * DEFAULT_SIZE_UNIT) {
                  _size = `${(size / 1024).toFixed(1)}kb`;
                }

                if (!type) {
                  type = getFileTypeByName(name)
                }

                let imgSrc = URL.createObjectURL(file.fileContent);
                if (type.indexOf('image') < 0 && type !== 'folder') {
                  imgSrc =  FileTypeIcon[FileVerifyMap[type].type]
                }

                return (
                  <div
                    className="file-item"
                    key={`file-item${index}`}
                    
                  >
                    <div className="file-item__cover">
                      <img src={imgSrc} />
                      <span className="file-name">{getEllipsText(name, 10)}</span>
                    </div>
                    <span className="file-item__size">{_size}</span>
                    <div className="file-item__status">
                      {
                        file.status === 'uploading' &&
                        <span>{file.progress}%</span>
                      }
                      {
                        file.status === 'success' &&
                        <span className="icon iconfont succ">&#xe710;</span>
                      }
                      {
                        file.status === 'fail' &&
                        [
                          <span className="icon iconfont fail">上传失败，请重试</span>,
                          <span
                            className="icon iconfont reupload"
                            onClick={() => this.handleReUpload(index)}
                          >&#xe75a;</span>
                        ]
                      }
                      {
                        file.status === 'waiting' &&
                        <span className="icon iconfont waiting">排队中</span>
                      }
                      {
                        (file.status === 'uploading' || file.status === 'waiting') &&
                        <span
                          className="icon iconfont close"
                          onClick={() => this.handleCancelUpload(file, index)}
                        >&#xe6ef;</span>
                      }

                    </div>
                    {
                      file.status === 'uploading' &&
                      <div
                        className="file-item__progress"
                        style={{
                          width: `${file.progress}%`
                        }}
                      ></div>
                    }
                   
                  </div>
                )
              })
              
            }
          </div>
        }
      </div>
    )
  }
}

export default UploadProgressModal;