import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import cx from 'classnames';
import ConfigProvider from '../config-provider';
import Message from '../message';
import zhCN from '../locale/zh-cn';
import dialog from './dialog';

const Dialog = ConfigProvider.config(dialog);

const noop = () => {};
const MESSAGE_TYPE = {
  alert: 'warning',
  confirm: 'help',
};

export const ModalInner = function ({
  type,
  messageProps = {},
  title,
  rtl,
  prefix = 'next-',
  content,
}) {
  return (
    <Message
      size="large"
      shape="addon"
      type={MESSAGE_TYPE[type]}
      {...messageProps}
      title={title}
      rtl={rtl}
      className={cx(`${prefix}dialog-message`, messageProps.className)}
    >
      {content}
    </Message>
  );
};

class Modal extends Component {
  static propTypes = {
    prefix: PropTypes.string,
    pure: PropTypes.bool,
    rtl: PropTypes.bool,
    type: PropTypes.oneOf(['alert', 'confirm']),
    title: PropTypes.node,
    content: PropTypes.node,
    messageProps: PropTypes.object,
    footerActions: PropTypes.array,
    /**
         * Callback function triggered when Ok button is clicked
         * @param {Object} event click event object
         * @returns {Promise} Optionally handles a Promise return object
         */
    onOk: PropTypes.func,
    /**
         * Callback function triggered when Cancel button is clicked
         * @param {Object} event click event object
         * @returns {Promise} Optionally handles a Promise return object
         */
    onCancel: PropTypes.func,
    /**
         * Callback function triggered when Close button is clicked
         * @param {Object} event click event object
         * @returns {Promise} Optionally handles a Promise return object
         */
    onClose: PropTypes.func,
    okProps: PropTypes.object,
    locale: PropTypes.object,
    needWrapper: PropTypes.bool,
    className: PropTypes.string,
  };

  static defaultProps = {
    prefix: 'next-',
    pure: false,
    messageProps: {},
    onOk: noop,
    onCancel: noop,
    onClose: noop,
    okProps: {},
    locale: zhCN.Dialog,
    needWrapper: true,
  };

  state = {
    visible: true,
    loading: false,
  };

  close = () => {
    this.setState({
      visible: false,
    });
  };

  loading = loading => {
    this.setState({
      loading,
    });
  };

  wrapper(fn, callback) {
    return (...args) => {
      const res = fn(...args);
      if (res && res.then) {
        this.loading(true);

        res.then(result => {
          this.loading(false);

          if (result !== false) {
            return callback();
          }
        }).catch(e => {
          this.loading(false);
          throw e;
        });
      } else if (res !== false) {
        return callback();
      }
    };
  }

  render() {
    const {
      prefix,
      type,
      title,
      content,
      messageProps,
      footerActions,
      onOk,
      onCancel,
      onClose,
      okProps,
      needWrapper,
      rtl,
      className,
      ...others
    } = this.props;
    const newTitle = needWrapper && type ? null : title;

    const newContent =
            needWrapper && type ? (
              <ModalInner
                type={type}
                messageProps={messageProps}
                title={title}
                rtl={rtl}
                prefix={prefix}
                content={content}
              />
            ) : (
              content
            );

    const newFooterActions =
            footerActions ||
            (type === 'alert'
              ? ['ok']
              : type === 'confirm'
                ? ['ok', 'cancel']
                : undefined);
    const newOnOk = this.wrapper(onOk, this.close);
    const newOnCancel = this.wrapper(onCancel, this.close);
    const newOnClose = this.wrapper(onClose, this.close);

    const { visible, loading } = this.state;
    okProps.loading = loading;

    const classNames = cx(`${prefix}dialog-quick`, className);

    return (
      <Dialog
        prefix={prefix}
        role="alertdialog"
        {...others}
        visible={visible}
        title={newTitle}
        rtl={rtl}
        footerActions={newFooterActions}
        onOk={this.state.loading ? noop : newOnOk}
        onCancel={newOnCancel}
        onClose={newOnClose}
        okProps={okProps}
        className={classNames}
      >
        {newContent}
      </Dialog>
    );
  }
}

const ConfigModal = ConfigProvider.config(Modal, { componentName: 'Dialog' });

/**
 * 创建对话框
 * @exportName show
 * @param {Object} config 配置项
 * @returns {Object} 包含有 hide 方法，可用来关闭对话框
 */
export const show = (config = {}) => {
  const container = document.createElement('div');
  const unmount = () => {
    if (config.afterClose) {
      config.afterClose();
    }
    ReactDOM.unmountComponentAtNode(container);
    container.parentNode.removeChild(container);
  };

  document.body.appendChild(container);
  const newContext = ConfigProvider.getContext();

  let instance; let
    myRef;

  ReactDOM.render(
    <ConfigProvider {...newContext}>
      <ConfigModal
        {...config}
        afterClose={unmount}
        ref={ref => {
          myRef = ref;
        }}
      />
    </ConfigProvider>,
    container,
    () => {
      instance = myRef;
    },
  );
  return {
    hide: () => {
      const inc = instance && instance.getInstance();
      inc && inc.close();
    },
  };
};

const methodFactory = type => (config = {}) => {
  config.type = type;
  return show(config);
};

/**
 * 创建警示对话框
 * @exportName alert
 * @param {Object} config 配置项
 * @returns {Object} 包含有 hide 方法，可用来关闭对话框
 */
export const alert = methodFactory('alert');

/**
 * 创建确认对话框
 * @exportName confirm
 * @param {Object} config 配置项
 * @returns {Object} 包含有 hide 方法，可用来关闭对话框
 */
export const confirm = methodFactory('confirm');
