import React, { Component } from 'react';
import { connect } from 'react-redux';
import JSZip from 'jszip';
import saveAs from 'file-saver';
import ConfirmModal from '../../components/ConfirmModal';
import ExportAssets from '../../components/ExportAssets';
import { getAssetsFromConfig } from 'utils/component';
import { transformScreenPackage } from 'services/screen';
import exportConfig from 'constants/export-config';
import { getMobileConstants } from 'models/mobile-constant';
import { exportInteractionById } from '@/services/interaction';

const { extension } = exportConfig;

interface IProps {
  constants: any[];
  screens: any[];
  version?: 'new' | 'old';
  getConstants: Function;
  onComplete: Function;
  onClose: (e: any) => void;
}

interface IState {
  screens: any[];
  completed: { id: number; name: string; zip: any }[];
}

class ExportModal extends Component<IProps, IState> {
  controller = window.AbortController && new AbortController();
  constructor(props) {
    super(props);
    this.state = {
      screens: this.props.screens,
      completed: [],
    };
  }

  onRequest = async (id) => {
    let { constants = [], getConstants } = this.props;
    if (!constants.length) {
      constants = await getConstants();
    }

    return exportInteractionById({ id, signal: this.controller.signal }).then(async (res) => {
      if (res) {
        let { mobileConfig, pagesConfig, mapConfig, info } = res;
        if (!window.appConfig.LOCAL) {
          if (this.props.version === 'old') {
            pagesConfig = await Promise.all(
              pagesConfig.map(async (d) => {
                let result = await transformScreenPackage({
                  from: 3.6,
                  to: 3.5,
                  data: {
                    componentsConfig: d.componentsConfig,
                    filterConfig: d.filterConfig,
                    panelConfig: d.panelConfig,
                  },
                });

                if (!result) {
                  return Promise.reject();
                }

                return {
                  ...d,
                  ...result,
                };
              }),
            );
          }
        }
        const data = {
          mobileConfig,
          pagesConfig,
          mapConfig,
          info: this.props.version === 'old' ? undefined : info,
        };

        const componentsConfig = pagesConfig.reduce(
          (all, item) => all.concat(item.componentsConfig),
          [],
        );
        const screensConfig = pagesConfig.reduce((all, item) => all.concat(item.screenConfig), []);
        const components = componentsConfig
          .filter((d) => !d.parent)
          .map((d) => {
            let base = JSON.parse(d.base);
            return `components/${base.module_name}/${base.version}/${base.module_name}.js`;
          });
        const thumbs = componentsConfig
          .filter((d) => !d.parent)
          .map((d) => {
            let base = JSON.parse(d.base);
            const constant = constants && constants.find((o) => o.moduleName === base.module_name);
            return constant && constant.thumb;
          })
          .filter((d) => d);
        const configAssets = componentsConfig.reduce(
          (all, item) => all.concat(getAssetsFromConfig(JSON.parse(item.config))),
          [],
        );
        const backgroundImg = screensConfig.reduce(
          (all, item) => all.concat(getAssetsFromConfig(JSON.parse(item.config))),
          [],
        );

        const files = Array.from(new Set(components)).filter((d) => d);
        const assets = Array.from(
          new Set(thumbs.concat(configAssets).concat(backgroundImg)),
        ).filter((d) => d);

        return { data, files, assets };
      } else {
        return Promise.reject();
      }
    });
  };

  onComplete = ({ id, zip, name }) => {
    const { screens } = this.state;
    if (screens.length === 1) {
      zip.generateAsync({ type: 'blob' }).then((blob) => {
        saveAs(blob, `${name}${extension.mobile}`);
        this.props.onComplete && this.props.onComplete();
      });
    } else {
      this.setState((prev) => ({
        completed: prev.completed.concat([{ id, zip, name }]),
      }));
    }
  };

  onRemove = (id) => {
    this.setState((prev) => ({
      screens: prev.screens.filter((d) => d.screenId != id),
    }));
  };

  onDownloadAll = async () => {
    const { completed } = this.state;
    const allZip = new JSZip();
    await Promise.all(
      completed.map((d) => {
        return new Promise((resolve) => {
          d.zip.generateAsync({ type: 'blob' }).then((blob) => {
            allZip.file(`${d.name.replace(/\//g, '_')}${extension.mobile}`, blob);
            resolve(blob);
          });
        });
      }),
    );
    allZip.generateAsync({ type: 'blob' }).then((blob) => {
      saveAs(blob, `screens(${completed.length})${extension.mobile}`);
      this.props.onClose(blob);
      this.props.onComplete && this.props.onComplete();
    });
  };

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

  render() {
    const { screens } = this.state;

    return (
      <ConfirmModal
        title="导出终端应用"
        visible={true}
        theme="black"
        onClose={this.props.onClose}
        onOk={this.onDownloadAll}
        footer={screens.length > 1 ? true : false}
        okText="下载"
        cancelText={''}>
        <div className="export-container">
          {screens.map((item) => (
            <ExportAssets
              key={item.id}
              name={`${item.name}_${item.id}`}
              id={item.id}
              onRequest={this.onRequest}
              onComplete={this.onComplete}
              onRemove={this.onRemove}
            />
          ))}
        </div>
      </ConfirmModal>
    );
  }
}

const mapStateToProps = ({ mobileConstants }) => {
  return {
    constants: mobileConstants.list,
  };
};

const mapDispatchToProps = {
  getConstants: getMobileConstants,
};

export default connect(mapStateToProps, mapDispatchToProps)(ExportModal);
