import React, { Component } from 'react';
import JSZip from 'jszip';
import saveAs from 'file-saver';
import ConfirmModal from '../../../../components/ConfirmModal';
import exportConfig from 'constants/export-config';
import EasyvProgress from 'components/EasyvProgress';
import chunk from 'lodash/chunk';

const { extension } = exportConfig;

interface IProps {
  fonts: any[];
  onComplete?: () => void;
}

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

export default class ExportFontsModal extends Component<IProps, IState> {
  controller: AbortController;
  zip: JSZip;
  constructor(props) {
    super(props);
    this.state = {
      visible: false,
      total: 0,
      exportIndex: 0,
      loaded: 0,
      maxIndex: 0,
      status: 'normal'
    };
  }

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

  startExport = () => {
    const { fonts } = this.props;
    this.setState(
      {
        total: fonts.length,
        loaded: 0,
        status: 'active'
      },
      () => {
        const fontChunk = chunk(fonts, 3);
        this.setState(
          {
            maxIndex: fontChunk.length - 1,
            exportIndex: 0
          },
          () => {
            this.zip = new JSZip();
            this.fontExportThrottle(fontChunk);
          }
        );
      }
    );
  };

  fontExportThrottle = async (fontChunk) => {
    // 节流
    const newFont = fontChunk[this.state.exportIndex];
    this.controller = window.AbortController && new AbortController();
    const result = await this.onExport(newFont);
    if (result) {
      this.setState({
        exportIndex: this.state.exportIndex + 1
      });
      this.fontExportThrottle(fontChunk);
    }
  };

  onExport = async (fonts) => {
    const { exportIndex, maxIndex } = this.state;
    const { fonts: globalFonts } = this.props;
    try {
      await Promise.all(fonts.map((d) => this.zipFiles(this.zip, d.src, d.fullName)));
      if (exportIndex >= maxIndex) {
        this.zip &&
          this.zip.generateAsync({ type: 'blob' }).then((blob) => {
            this.hideModal();
            this.props.onComplete && this.props.onComplete();
            saveAs(blob, `fonts(${globalFonts.length})${extension.font}`);
          });
        this.setState({
          status: 'success'
        });
      } else {
        return true;
      }
    } catch (error) {
      this.controller && this.controller.abort();
      this.setState({
        status: 'exception'
      });
    }
  };

  zipFiles = (zip, src, name) => {
    const signal = this.controller && this.controller.signal;

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

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

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

  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} maskClosable={false}>
          <EasyvProgress
            percent={percent}
            status={status}
            title={this.renderStatus(status)}
            statusMsg={{ exception: <i className="icon iconfont icon-btn_reload click" onClick={this.startExport} title="重试" /> }}
          />
        </ConfirmModal>
      </span>
    );
  }
}
