import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { Portal } from 'amos-framework';

const IS_REACT_16 = !!ReactDOM.createPortal;

/**
 * portal component
 *
 * @param {any} WrappedComponent
 * @param {any} options
 * @returns enhance Component
 */
export default function(WrappedComponent, options){

  class WrapperComponent extends Component {

    static propTypes = {
      visible: PropTypes.bool,
      getContainer: PropTypes.func
    };

    constructor(props) {
      super(props);
      this.state = {
        visible: false
      };
    }

    shouldComponentUpdate({ visible }) {
      return !!(this.props.visible || visible);
    }

    componentWillUnmount() {
      if (IS_REACT_16) {
        return;
      }
      if (this.props.visible) {
        this.renderComponent({
          afterLeave: this.removeContainer,
          onLeave() {
          },
          visible: false
        });
      } else {
        this.removeContainer();
      }
    }

    getComponent = (extra = {}) => {
      return (
        <WrappedComponent
          ref={node => this._component = node}
          {...this.props}
          {...extra}
          key="portal-wrapper"
        />
      );
    }

    getContainer = () => {
      if (this.props.getContainer) {
        return this.props.getContainer();
      }
      const container = document.createElement('div');
      document.body.appendChild(container);
      return container;
    }

    removeContainer = () => {
      if (this._container) {
        const container = this._container;
        ReactDOM.unmountComponentAtNode(container);
        container.parentNode.removeChild(container);
        this._container = null;
      }
    }

    renderComponent = (componentArg, ready) => {
      const { visible } = this.props;

      if (!visible || this._component) {
        if (!this._container) {
          this._container = this.getContainer();
        }
        const component = this.getComponent(componentArg);

        ReactDOM.unstable_renderSubtreeIntoContainer(this,
          component, this._container,
          function callback() {
            this._component = this;
            if (ready) {
              ready.call(this);
            }
          });
      }
    }

    render() {
      const { visible } = this.props;

      let portal = null;

      if (!IS_REACT_16) {
        return portal;
      }

      if (visible || this._component) {
        portal = (
          <Portal getContainer={this.getContainer}>
            {this.getComponent()}
          </Portal>
        );
      }

      return portal;
    }
  }

  return WrapperComponent;
}
