import React from 'react';
import RcUpload from 'rc-upload';
import UploadList from './uploadList';
import getFileItem from './getFileItem';
import classNames from 'classnames';
const prefixCls = 'ant-upload';

function noop() {
}

function T() {
  return true;
}

// Fix IE file.status problem
// via coping a new Object
function fileToObject(file) {
  return {
    lastModified: file.lastModified,
    lastModifiedDate: file.lastModifiedDate,
    name: file.filename || file.name,
    size: file.size,
    type: file.type,
    uid: file.uid,
    response: file.response,
    error: file.error,
    percent: 0,
    originFileObj: file,
  };
}

/**
 * 生成Progress percent: 0.1 -> 0.98
 *   - for ie
 */
function genPercentAdd() {
  let k = 0.1;
  const i = 0.01;
  const end = 0.98;
  return function (s) {
    let start = s;
    if (start >= end) {
      return start;
    }

    start += k;
    k = k - i;
    if (k < 0.001) {
      k = 0.001;
    }
    return start * 100;
  };
}

class UploadDragger extends React.Component {
  render() {
    return <Upload {...this.props} type="drag" style={{ height: this.props.height }} />;
  }
}

export default class Upload extends React.Component {
  static Dragger = UploadDragger;

  static defaultProps = {
    type: 'select',
    // do not set
    // name: '',
    multiple: false,
    action: '',
    data: {},
    accept: '',
    onChange: noop,
    beforeUpload: T,
    showUploadList: true,
    listType: 'text', // or pictrue
    className: '',
  }

  constructor(props) {
    super(props);
    this.state = {
      fileList: this.props.fileList || this.props.defaultFileList || [],
      dragState: 'drop'
    };
  }

  onStart = (file) => {
    if (this.recentUploadStatus === false) return;

    let targetItem;
    let nextFileList = this.state.fileList.concat();
    if (file.length > 0) {
      targetItem = file.map(f => {
        const fileObject = fileToObject(f);
        fileObject.status = 'uploading';
        return fileObject;
      });
      nextFileList = nextFileList.concat(targetItem);
    } else {
      targetItem = fileToObject(file);
      targetItem.status = 'uploading';
      nextFileList.push(targetItem);
    }
    this.onChange({
      file: targetItem,
      fileList: nextFileList
    });
    // fix ie progress
    if (!window.FormData) {
      this.autoUpdateProgress(0, targetItem);
    }
  }

  autoUpdateProgress(percent, file) {
    const getPercent = genPercentAdd();
    let curPercent = 0;
    this.progressTimer = setInterval(() => {
      curPercent = getPercent(curPercent);
      this.onProgress({
        percent: curPercent
      }, file);
    }, 200);
  }

  removeFile(file) {
    let fileList = this.state.fileList;
    let targetItem = getFileItem(file, fileList);
    let index = fileList.indexOf(targetItem);
    if (index !== -1) {
      fileList.splice(index, 1);
      return fileList;
    }
    return null;
  }

  onSuccess = (response, file) => {
    this.clearProgressTimer();
    try {
      if (typeof response === 'string') {
        response = JSON.parse(response);
      }
    } catch (e) {/* do nothing */}
    let fileList = this.state.fileList;
    let targetItem = getFileItem(file, fileList);
    // 之前已经删除
    if (targetItem) {
      targetItem.status = 'done';
      targetItem.response = response;
      this.onChange({
        file: targetItem,
        fileList
      });
    }
  }

  onProgress = (e, file) => {
    let fileList = this.state.fileList;
    let targetItem = getFileItem(file, fileList);
    if (!targetItem) return;
    targetItem.percent = e.percent;
    this.onChange({
      event: e,
      file: targetItem,
      fileList: this.state.fileList
    });
  }

  onError = (error, response, file) => {
    this.clearProgressTimer();
    let fileList = this.state.fileList;
    let targetItem = getFileItem(file, fileList);
    targetItem.error = error;
    targetItem.response = response;
    targetItem.status = 'error';
    this.handleRemove(targetItem);
  }

  beforeUpload(file) {
    this.recentUploadStatus = this.props.beforeUpload(file);
    return this.recentUploadStatus;
  }

  handleRemove(file) {
    let fileList = this.removeFile(file);
    if (fileList) {
      this.onChange({
        file,
        fileList,
      });
    }
  }

  handleManualRemove = (file) => {
    /*eslint-disable */
    file.status = 'removed';
    /*eslint-enable */
    this.handleRemove(file);
  }

  onChange = (info) => {
    this.setState({
      fileList: info.fileList
    });
    this.props.onChange(info);
  }

  componentWillReceiveProps(nextProps) {
    if ('fileList' in nextProps) {
      this.setState({
        fileList: nextProps.fileList || [],
      });
    }
  }

  onFileDrop = (e) => {
    this.setState({
      dragState: e.type
    });
  }

  clearProgressTimer() {
    clearInterval(this.progressTimer);
  }

  render() {
    let type = this.props.type || 'select';
    let props = {
      ...this.props,
      onStart: this.onStart,
      onError: this.onError,
      onProgress: this.onProgress,
      onSuccess: this.onSuccess,
      beforeUpload: this.beforeUpload,
    };
    let uploadList;
    if (this.props.showUploadList) {
      uploadList = (
        <UploadList listType={this.props.listType}
          items={this.state.fileList}
          onRemove={this.handleManualRemove} />
      );
    }
    if (type === 'drag') {
      let dragUploadingClass = this.state.fileList.some(file => file.status === 'uploading')
        ? `${prefixCls}-drag-uploading` : '';
      let draggingClass = this.state.dragState === 'dragover'
        ? `${prefixCls}-drag-hover` : '';
      return (
        <span className={this.props.className}>
          <div className={`${prefixCls} ${prefixCls}-drag ${dragUploadingClass} ${draggingClass}`}
            onDrop={this.onFileDrop}
            onDragOver={this.onFileDrop}
            onDragLeave={this.onFileDrop}>
            <RcUpload {...props}>
              <div className={`${prefixCls}-drag-container`}>
                {this.props.children}
              </div>
            </RcUpload>
          </div>
          {uploadList}
        </span>
      );
    } else if (type === 'select') {
      const uploadButtonCls = classNames({
        [prefixCls]: true,
        [`${prefixCls}-select`]: true,
        [`${prefixCls}-select-${this.props.listType}`]: true,
      });
      if (this.props.listType === 'picture-card') {
        return (
          <span className={this.props.className}>
            {uploadList}
            <div className={uploadButtonCls}>
              <RcUpload {...props}>
                {this.props.children}
              </RcUpload>
            </div>
          </span>
        );
      }
      return (
        <span className={this.props.className}>
          <div className={uploadButtonCls}>
            <RcUpload {...props}>
              {this.props.children}
            </RcUpload>
          </div>
          {uploadList}
        </span>
      );
    }
  }
}
