import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import uppercamelcase from 'uppercamelcase';
import { Button, Icon, Feedback, Progress } from '@icedesign/base';
import babelPluginTransfromDecoratorLegacy from 'babel-plugin-transform-decorators-legacy';
import '@ali/ice-loading/lib/style';
import { babelReady, BASE_CDN, loadScriptAsync } from '../../utils';
// import request from '../../service/request';
import { getReactMaterials, getVueMaterials } from '../../service/database';
import externals from '../../service/common-externals';
import './BlockPreviewPage.scss';

const Toast = Feedback.toast;
// const UNPKG = 'https://unpkg.com';
// const UNPKG = 'https://unpkg.zhimg.com'; // cdn hosted by zhimg
// const UNPKG_META_KEYWORDS = 'meta'; // unpkg 官方用 meta, zhimg 和 alibaba-ice 用的是 json
const scriptLoaded = {};

export default class BlockPreviewPage extends Component {
  static displayName = 'BlockPreviewPage';

  static propTypes = {};

  static defaultProps = {};

  constructor(props) {
    super(props);
    const { router } = props;
    this.state = {
      loading: true,
      blockData: {},
      loadingPercentage: 0,
      loadingMessage: '初始化预览编译器...',
    };

    this.isLayout = /^\/layout/.test(router.location.pathname);
  }

  installRequire = () => {
    eval(`
      window.require = function require(p){
        var path = require.resolve(p);
        var mod = require.modules[path];
        if (!mod) throw new Error('failed to require "' + p + '"');
        if (!mod.exports) {
          mod.exports = {};
          mod.call(mod.exports, mod, mod.exports, require.relative(path));
        }
        return mod.exports;
      }

      require.modules = {};

      require.resolve = function (path){
        var orig = path;
        var reg = path + '.js';
        var json = path + '.json';
        var index = path + '/index.js';
        return require.modules[reg] && reg
          || require.modules[json] && json
          || require.modules[index] && index
          || orig;
      };

      require.register = function (path, fn){
        require.modules[path] = fn;
      };

      require.relative = function (parent) {
        return function(p){
          if ('.' != p.charAt(0)) return require(p);
          var path = parent.split('/');
          var segs = p.split('/');
          path.pop();

          for (var i = 0; i < segs.length; i++) {
            var seg = segs[i];
            if ('..' == seg) path.pop();
            else if ('.' != seg) path.push(seg);
          }

          return require(path.join('/'));
        };
      };
    `);
  };

  hijactAJAX = () => {
    // 仅对 ghpages 做劫持
    if (!/alibaba\.github\.io/.test(location.href)) {
      return;
    }

    this.rawOpen = XMLHttpRequest.prototype.open;
    const _this = this;
    // eslint-disable-next-line
    XMLHttpRequest.prototype.open = function(...args) {
      if (/^\/mock/.test(args[1])) {
        args[1] = '/ice' + args[1];
      }
      return _this.rawOpen.apply(this, args);
    };
  };

  componentWillUnmount() {
    if (this.rawOpen) {
      XMLHttpRequest.prototype.open = this.rawOpen;
    }
  }

  async componentDidMount() {
    if (this.isLayout) {
      this.prev();
      return;
    }

    this.hijactAJAX();
    const { router } = this.props;
    const { type = 'react' } = this.props.location.query;
    const blockName = router.params.blockName;
    if (!blockName) {
      // todo redirect 502
    }

    const { blocks } = await getReactMaterials();

    const blockData = blocks.find((item) => item.name === blockName);
    if (!blockData) {
      Toast.error('Sorry 找不到改区块, 5s 后返回.');
      setTimeout(() => {
        this.props.router.goBack();
      }, 5000);
    }

    const blockClassName = uppercamelcase(blockData.name);
    const blockVersion = blockData.source.version;
    const cdnOrigin = /debug/.test(window.location.href)
      ? 'g-assets.daily.taobao.net'
      : 'g.alicdn.com';
    this.loadStyle(
      `https://${cdnOrigin}/code/iceland/${blockClassName}///${blockVersion}.css`
    );
    await loadScriptAsync(BASE_CDN);
    await loadScriptAsync(
      `https://${cdnOrigin}/code/iceland/${blockClassName}///${blockVersion}.js`
    );
    // eslint-disable-next-line
    this.setState(
      {
        blockData,
        loading: false,
      },
      () => {
        // https://g-assets.daily.taobao.net/code/iceland/CircleProgress/0.1.0.js
        const entry = React.createElement(
          window['IceBlock' + blockClassName].default,
          {}
        );
        ReactDOM.render(entry, this.mountNode);
      }
    );
  }

  loadStyle = (url) => {
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = url;
    document.head.appendChild(link);
  };

  resolveMapCache = {};

  compileJavaScript = (es6) => {
    return babelReady().then((babel) => {
      return new Promise((resolve, reject) => {
        try {
          const compiled = babel.transform(es6, {
            presets: ['es2015', 'react', 'stage-0'],
            plugins: [babelPluginTransfromDecoratorLegacy],
          });
          resolve(compiled);
        } catch (err) {
          reject(err);
        }
      });
    });
  };

  loadSCSS = () => {
    if (window.sass) {
      return Promise.resolve(window.sass);
    } else {
      return this.loadScriptAsync(
        'https://g.alicdn.com/code/iceland/sass.js/0.10.7/sass.js'
      ).then(() => {
        return window.sass;
      });
    }
  };
  loadScriptAsync = (url) => {
    if (Array.isArray(scriptLoaded[url])) {
      // 等待加载的 callback 列表
      return new Promise((resolve) => {
        scriptLoaded[url].push(resolve);
      });
    } else if (scriptLoaded[url]) {
      return Promise.resolve();
    } else {
      return new Promise((resolve) => {
        const script = document.createElement('script');
        script.src = url;
        script.onload = () => {
          scriptLoaded[url].forEach((done) => {
            done();
          });
          scriptLoaded[url] = true;
        };
        scriptLoaded[url] = [resolve];
        document.body.appendChild(script);
      });
    }
  };
  compileSCSS = (scss) => {
    return this.loadSCSS().then((sass) => {
      return new Promise((resolve) => {
        sass.compile(scss, (result) => {
          resolve({ code: result.text || '' });
        });
      });
    });
  };

  setLoadingMessage = (msg) => {
    const { loadingPercentage } = this.state;
    if (msg && msg !== this.state.loadingMessage) {
      this.setState({
        loadingMessage: msg,
        loadingPercentage: parseInt(
          loadingPercentage + (100 - loadingPercentage) * 0.3
        ),
      });
    }
  };

  generateRenderCode = () => {
    const { loading, blockData } = this.state;
    if (blockData.categories.some((cat) => cat.name === 'modal')) {
      return `
        var Button = window['@icedesign/base'].Button;
        var Comp = window['${blockData.npm}'].default;
        var closeDialog = function() {
          Comp.hide();
        };
        var props = {
          onClick: function() {
            Comp.show({
              onClose: closeDialog,
              onCancel: closeDialog,
              onOk: closeDialog,
            });
          },
          type: 'primary',
        };
        ReactDOM.render(React.createElement(Button, props, '点击展示模态框'), document.querySelector('#ice-conatiner'));
      `;
    } else {
      return `
        var Comp = window['${blockData.npm}'].default;
        var props = {};
        ReactDOM.render(React.createElement(Comp, props), document.querySelector('#ice-conatiner'));
      `;
    }
  };

  prev = () => {
    const { params, location, router } = this.props;
    if (/^\/layout/.test(location.pathname)) {
      router.replace(`/ice/layout/${params.blockName}`);
    } else {
      router.replace(`/ice/block/${params.blockName}`);
    }
  };

  render() {
    const {
      loading,
      loadingPercentage,
      loadingMessage,
      blockData,
    } = this.state;

    if (loading) {
      return (
        <div>
          <div style={{ marginBottom: '20px' }}>
            <Button type="primary" size="small" onClick={this.prev}>
              <Icon type="arrow-double-left" />
              返回详情
            </Button>
          </div>
          <div style={styles.loadingContainer}>
            <Progress
              percent={loadingPercentage}
              size="small"
              style={{
                marginTop: '175px',
                marginBottom: '15px',
              }}
            />
            <span style={styles.loadingMessage}>{loadingMessage}</span>
          </div>
        </div>
      );
    } else {
      return (
        <div className="block-preview-page">
          <div style={styles.title}>
            <div style={{ marginBottom: '20px' }}>
              <Button type="primary" size="small" onClick={this.prev}>
                <Icon type="arrow-double-left" />
                返回
              </Button>
            </div>
            <div
              style={{
                marginTop: '10px',
                fontSize: '14px',
                marginBottom: '20px',
              }}
            >
              {blockData.className} - {blockData.title}
            </div>
          </div>

          <div
            style={{ overflow: 'hidden' }}
            ref={(ref) => {
              this.mountNode = ref;
            }}
          />
        </div>
      );
    }
  }
}

const styles = {
  destStyle: {
    border: 'none',
    width: '100%',
    minHeight: '500px',
    margin: '20px 0',
    boxShadow: '0 0 20px #808080',
  },
  title: {
    fontSize: '16px',
  },
  loadingContainer: {
    width: '960px',
    margin: '0 auto',
    textAlign: 'center',
  },
  loadingMessage: {
    fontSize: '13px',
    fontWeight: 'bold',
  },
};
