import React, { Component } from 'react';
import ConfirmModal from '../../../../components/ConfirmModal';
import JSZip from 'jszip';
import saveAs from 'file-saver';
import exportConfig from 'constants/export-config';
import { exportConstants } from 'models/constant';
import { connect } from 'react-redux';
import EasyvProgress from 'components/EasyvProgress';
import {getAssetsUrl} from 'utils/utils';

const { extension } = exportConfig;

interface IProps {
  list: string[];
  exportConstants: (ids: string[]) => Promise<{ configs: any; orderConfig: any; staticList: any }>;
  onComplete?: () => void;
  children: React.ReactElement;
}

interface IState {
  visible: boolean;
  total: number;
  loaded: number;
  status: 'normal' | 'active' | 'success' | 'exception';
}

class ExportConstantModal extends Component<IProps, IState> {
  controller: AbortController;
  constructor(props) {
    super(props);
    this.state = {
      visible: false,
      total: 0,
      loaded: 0,
      status: 'normal'
    };
  }

  showModal = () => {
    this.setState({
      visible: true
    });

    this.startExport();
  };

  startExport = async () => {
    this.controller = window.AbortController && new AbortController();

    this.setState({
      total: 0,
      loaded: 0,
      status: 'active'
    });

    const { list } = this.props;
    const result = await this.props.exportConstants(list);

    if (result) {
      const { configs, orderConfig, staticList = [] } = result;

      const zip = new JSZip();

      // 数据
      zip.file('constant.json', JSON.stringify(configs));
      zip.file('orderConfig.json', JSON.stringify(orderConfig));

      // 文件
      const constantFiles = configs.map((d) => this.zipFiles(zip, `components/${d.moduleName}/${d.version}/${d.moduleName}.js`));
      const thumbFiles = configs
        .filter((d) => d.thumb)
        .map((d) =>
          this.zipFiles(zip, d.thumb).catch(() => {
            console.error(`${d.thumb} get failed`);
          })
        );
      const staticImgs = staticList
        .reduce((total, item) => total.concat(item), [])
        .map((src) => this.zipFiles(zip, `components/static-image/${src}`));
      const all = constantFiles.concat(thumbFiles).concat(staticImgs);

      this.setState({
        total: all.length
      });

      await Promise.all(all);

      this.setState({
        status: 'success'
      });

      zip.generateAsync({ type: 'blob' }).then((blob) => {
        this.hideModal();
        this.props.onComplete && this.props.onComplete();
        if (list.length === 1) {
          saveAs(blob, `${list[0]}${extension.constant}`);
        } else {
          saveAs(blob, `constant(${list.length})${extension.constant}`);
        }
      });
    } else {
      this.controller && this.controller.abort();
      this.setState({
        status: 'exception'
      });
    }
  };

  hideModal = () => {
    this.controller && this.controller.abort();
    this.setState({
      visible: false
    });
  };

  zipFiles = (zip, src) => {
    const signal = this.controller && this.controller.signal;
    const path = src.slice(0, src.lastIndexOf('/'));
    const name = src.slice(src.lastIndexOf('/') + 1);
    const url = getAssetsUrl(`${src}`)

    return fetch(url, { signal, cache: 'no-store' })
      .then((res) => {
        if (res.status === 200) {
          return res.blob();
        } else {
          return Promise.reject(res.statusText);
        }
      })
      .then((result) => {
        this.setState((prev) => ({
          loaded: prev.loaded + 1
        }));
        zip.folder(path).file(name, result);
      });
  };

  renderStatus = (status) => {
    switch (status) {
      case 'exception':
        return '导出失败，请重试';
      case 'success':
        return '导出成功';
      default:
        return '组件正在导出，请稍后...';
    }
  };

  componentWillUnmount() {
    this.controller && this.controller.abort();
  }

  render() {
    const { visible, total, loaded, status } = this.state;
    const percent = loaded ? Math.round((loaded / total) * 100) : 0;

    return (
      <span>
        <span onClick={this.showModal}>{this.props.children}</span>
        <ConfirmModal visible={visible} title="组件导出" onClose={this.hideModal} footer={false} maskClosable={false}>
          <EasyvProgress
            statusMsg={{ exception: <i className="icon iconfont icon-btn_reload click" onClick={this.startExport} title="重试" /> }}
            percent={percent}
            status={status}
            title={this.renderStatus(status)}
          />
        </ConfirmModal>
      </span>
    );
  }
}

const mapDispatchToProps = {
  exportConstants
};

export default connect(null, mapDispatchToProps)(ExportConstantModal);
