import React, { useState, useEffect, useCallback } from 'react';
import { connect } from 'react-redux';
import JSZip from 'jszip';
import saveAs from 'file-saver';
import ExportModal from './ExportModal';
import { exportThemes } from 'models/theme';
import exportConfig from 'constants/export-config';
import { getAssetsFromConfig } from 'utils/component';
import { getAssetsUrl } from 'utils/utils';

const { extension } = exportConfig;

function ExportContainer({ children, list, exportThemes, onComplete } : {
  children: React.ReactElement;
  list: any;
  exportThemes: (params) => Promise<{ configs: any}>;
  onComplete?: () => void;
}) {
  const [visible, setVisible] = useState(false);
  const [total, setTotal] = useState(0);
  const [loaded, setLoaded] = useState(0);
  const [status, setStatus] = useState('normal');
  const [retryCount, setRetryCount] = useState(0);

  useEffect(() => {
    let controller = window.AbortController && new AbortController();
    const zipFiles = (zip, src) => {
      const signal = controller && controller.signal;
      const path = src.slice(0, src.lastIndexOf('/'));
      const name = src.slice(src.lastIndexOf('/') + 1);

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

    async function startExport() {
      const result = await exportThemes(list);

      if (result) {
        const { configs } = result;
        const zip = new JSZip();

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

        // 文件
        const configAssets = configs
          .reduce((acc, d) => acc.concat(getAssetsFromConfig(JSON.parse(d.config))), [])
          .map((d) =>
            zipFiles(zip, d).catch(() => {
              console.error(`${d} get failed`);
            })
          );

        const thumbFiles = configs
          .filter((d) => d.thumb)
          .map((d) =>
            zipFiles(zip, d.thumb).catch(() => {
              console.error(`${d.thumb} get failed`);
            })
          );
        let all = configAssets.concat(thumbFiles);

        setTotal(all.length);

        await Promise.all(all);

        setStatus('success');

        zip.generateAsync({ type: 'blob' }).then((blob) => {
          hideModal();
          onComplete && onComplete();
          if (list.length === 1) {
            saveAs(blob, `主题_${configs[0].name}${extension.theme}`);
          } else {
            saveAs(blob, `主题(${list.length})${extension.theme}`);
          }
        });
      } else {
        controller && controller.abort();
        setStatus('exception');
      }
    }

    if (visible) {
      setTotal(0);
      setLoaded(0);
      setStatus('active');

      startExport();
    }
    return () => {
      controller && controller.abort();
    };
  }, [visible, retryCount, list]);

  const hideModal = useCallback(() => {
    setVisible(false);
  }, []);

  const handleRestart = useCallback(() => {
    setRetryCount((prev) => prev + 1);
  }, []);

  const percent = loaded ? Math.round((loaded / total) * 100) : 0;

  return (
    <span>
      <span onClick={() => setVisible(true)}>{children}</span>
      <ExportModal
        visible={visible}
        title="主题导出"
        status={status}
        statusText={status === 'success' ? '导出成功' : status === 'exception' ? '导出失败，请重试' : '主题正在导出，请稍后...'}
        percent={percent}
        onCancel={hideModal}
        onRestart={handleRestart}
      />
    </span>
  );
}

const mapDispatchToProps = {
  exportThemes
};

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