import React, { PureComponent, Fragment } from 'react';

import { Balloon, Badge, Dialog } from '@alifd/next';
import Editor from '@ali/lowcode-editor-framework';
import {
  PluginConfig,
  PluginClass,
} from '@ali/lowcode-editor-framework/lib/definitions';
import TopIcon from '../TopIcon';

import './index.scss';

export interface TopPluginProps {
  active?: boolean;
  config: PluginConfig;
  disabled?: boolean;
  editor: Editor;
  locked?: boolean;
  marked?: boolean;
  onClick?: () => void;
  pluginClass: PluginClass | undefined;
}

export interface TopPluginState {
  dialogVisible: boolean;
}

export default class TopPlugin extends PureComponent<
  TopPluginProps,
  TopPluginState
> {
  static displayName = 'LowcodeTopPlugin';

  static defaultProps = {
    active: false,
    config: {},
    disabled: false,
    marked: false,
    locked: false,
    onClick: (): void => {},
  };

  constructor(props, context) {
    super(props, context);
    this.state = {
      dialogVisible: false,
    };
  }

  componentDidMount(): void {
    const { config, editor } = this.props;
    const pluginKey = config && config.pluginKey;
    if (editor && pluginKey) {
      editor.on(`${pluginKey}.dialog.show`, this.handleShow);
      editor.on(`${pluginKey}.dialog.close`, this.handleClose);
    }
  }

  componentWillUnmount(): void {
    const { config, editor } = this.props;
    const pluginKey = config && config.pluginKey;
    if (editor && pluginKey) {
      editor.off(`${pluginKey}.dialog.show`, this.handleShow);
      editor.off(`${pluginKey}.dialog.close`, this.handleClose);
    }
  }

  handleShow = (): void => {
    const { disabled, config, onClick, editor } = this.props;
    const pluginKey = config && config.pluginKey;
    if (disabled || !pluginKey) return;
    this.handleOpen();
    // 考虑到弹窗情况，延时发送消息
    setTimeout((): void => {
      editor.emit(`${pluginKey}.plugin.activate`);
    }, 0);
    onClick && onClick();
  };

  handleClose = (): void => {
    const { config, editor } = this.props;
    const pluginKey = config && config.pluginKey;
    const plugin = editor.plugins && editor.plugins[pluginKey];
    if (plugin) {
      plugin.close().then((): void => {
        this.setState({
          dialogVisible: false,
        });
      });
    }
  };

  handleOpen = (): void => {
    // todo dialog类型的插件初始时拿不动插件实例
    this.setState({
      dialogVisible: true,
    });
  };

  renderIcon = (clickCallback): React.ReactNode => {
    const {
      active,
      disabled,
      marked,
      locked,
      config,
      onClick,
      editor,
    } = this.props;
    const { pluginKey, props } = config || {};
    const { icon, title } = props || {};
    const node = (
      <TopIcon
        className={`lowcode-top-plugin ${pluginKey}`}
        active={active}
        disabled={disabled}
        locked={locked}
        icon={icon}
        title={title}
        onClick={(): void => {
          if (disabled) return;
          // 考虑到弹窗情况，延时发送消息
          setTimeout((): void => {
            editor.emit(`${pluginKey}.plugin.activate`);
          }, 0);
          clickCallback && clickCallback();
          onClick && onClick();
        }}
      />
    );
    return marked ? <Badge dot>{node}</Badge> : node;
  };

  render(): React.ReactNode {
    const {
      active,
      marked,
      locked,
      disabled,
      config,
      editor,
      pluginClass: Comp,
    } = this.props;
    const { pluginKey, pluginProps, props, type } = config || {};
    const { onClick, title } = props || {};
    const { dialogVisible } = this.state;
    if (!pluginKey || !type) return null;
    const node = Comp ? (
      <Comp
        editor={editor}
        active={active}
        locked={locked}
        disabled={disabled}
        config={config}
        onClick={(): void => {
          onClick && onClick.call(null, editor);
        }}
        {...pluginProps}
      />
    ) : null;

    switch (type) {
      case 'LinkIcon':
        return (
          <a {...props.linkProps}>
            {this.renderIcon((): void => {
              onClick && onClick.call(null, editor);
            })}
          </a>
        );
      case 'Icon':
        return this.renderIcon((): void => {
          onClick && onClick.call(null, editor);
        });
      case 'DialogIcon':
        return (
          <Fragment>
            {this.renderIcon((): void => {
              onClick && onClick.call(null, editor);
              this.handleOpen();
            })}
            <Dialog
              onOk={(): void => {
                editor.emit(`${pluginKey}.dialog.onOk`);
                this.handleClose();
              }}
              onCancel={this.handleClose}
              onClose={this.handleClose}
              title={title}
              style={{
                width: 500,
                ...(props.dialogProps && props.dialogProps.style),
              }}
              {...props.dialogProps}
              visible={dialogVisible}
            >
              {node}
            </Dialog>
          </Fragment>
        );
      case 'BalloonIcon':
        return (
          <Balloon
            trigger={this.renderIcon((): void => {
              onClick && onClick.call(null, editor);
            })}
            triggerType={['click', 'hover']}
            {...props.balloonProps}
          >
            {node}
          </Balloon>
        );
      case 'Custom':
        return marked ? <Badge dot>{node}</Badge> : node;
      default:
        return null;
    }
  }
}
