import React, { Component } from 'react';
import JSZip from 'jszip';
import isBoolean from 'lodash/isBoolean';
import styles from './index.less';
import EasyvProgress from 'components/EasyvProgress';
import { RedoOutlined, DeleteSquareOutlined, CloseOutlined, CheckOutlined } from '@easyv/react-icons';
import IconWrapper from 'components/IconWrapper';
import {getAssetsUrl } from 'utils/utils';

interface IProps {
  id: number;
  start?: boolean;
  name: string;
  trailColor?: string;
  onRequest: (id) => Promise<{ data: any; files: any; assets: any }>;
  onComplete: (param: { id: number; zip: JSZip; name: string }) => void;
  onRemove: (id) => void;
  onError?: (id) => void;
}

interface IState {
  total: number;
  loaded: number;
  status: 'success' | 'normal' | 'exception' | 'active';
}
type TitleProps = { title: string; style?: React.CSSProperties };

const Title = (props: TitleProps) => {
  const { style, title } = props;
  return (
    <span style={style} className={styles.title}>
      {title}
    </span>
  );
};

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

  componentDidMount() {
    if (!isBoolean(this.props?.start) || (isBoolean(this.props?.start) && this.props?.start)) {
      this.startExport();
    }
  }

  componentDidUpdate(prevProps) {
    if (!prevProps?.start && this.props?.start && !this.controller) {
      this.startExport();
    }
  }

  startExport = () => {
    this.controller = window.AbortController && new AbortController();
    const { onRequest, id } = this.props;

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

    onRequest(id)
      .then((res) => {
        const { data, files, assets } = res;
        this.onExport(data, files, assets);
      })
      .catch((error) => {
        console.error(error);
        this.setState({
          status: 'exception'
        });
        this.props?.onError?.(id);
      });
  };

  onExport = async (data = {}, files, assets) => {
    const { id, name, onComplete } = this.props;
    const zip = new JSZip();
    Object.entries(data).map((d) => {
      zip.file(`${d[0]}.json`, JSON.stringify(d[1]));
    });
    const all = files
      .map((d) => {
        return this.zipFiles(zip, d)
      })
      .concat(
        assets.map(d=>{
          // 资源地址存在//情况，做移除
          return d.replace(/^(\/|\\){1,}/,'')
        })
          .filter((e) => !/components\/area\//.test(e))
          .map((d) =>
            this.zipFiles(zip, d).catch(() => {
              console.error(`export ${d} failed`);
            })
          )
      );
    this.setState({
      total: all.length
    });

    try {
      await Promise.all(all);
      this.setState(
        () => ({
          status: 'success'
        }),
        () => {
          onComplete && onComplete({ id, zip, name });
        }
      );
    } catch (error) {
      console.error(error);
      this.controller && this.controller.abort();
      this.setState({
        status: 'exception'
      });
      this.props?.onError?.(id);
    }
  };

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

  zipFiles = async (zip, src) => {
    const path = src.slice(0, src.lastIndexOf('/'));
    const name = src.slice(src.lastIndexOf('/') + 1);

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

  render() {
    const { name, id } = this.props;
    const { total, loaded, status } = this.state;
    const percent = status === 'success' ? 100 : loaded ? Math.round((loaded / total > 1 ? 1 : loaded / total) * 100) : 0;

    return (
      <EasyvProgress
        title={name}
        percent={percent}
        status={status}
        statusMsg={{
          success: (
            <div className={styles.flexCenter}>
              <IconWrapper icon={CheckOutlined} style={{ color: '#00A755', fontSize: 14, marginRight: 6 }} />
              <Title title="打包成功" />
              <IconWrapper
                icon={DeleteSquareOutlined}
                title="移除"
                className={styles.publicIcon}
                onClick={() => {
                  this.props.onRemove(id);
                  this.controller && this.controller.abort();
                }}
              />
            </div>
          ),
          exception: (
            <div className={styles.flexCenter}>
              <IconWrapper icon={CloseOutlined} className={styles.exception} />
              <Title title="打包失败" style={{ marginRight: 6, color: '#fff' }} />
              <IconWrapper
                icon={RedoOutlined}
                style={{ marginRight: 4 }}
                className={styles.publicIcon}
                title="重试"
                onClick={this.startExport}
              />
              <IconWrapper
                icon={DeleteSquareOutlined}
                className={styles.publicIcon}
                title="移除"
                onClick={() => {
                  this.props.onRemove(id);
                  this.controller && this.controller.abort();
                }}
              />
            </div>
          ),
          normal: <span style={{ marginRight: 8 }}>{percent + '%'}</span>,
          active: <span style={{ marginRight: 8 }}>{percent + '%'}</span>
        }}
      />
    );
  }
}

export default ExportAssets;
