/**
 * @file Drawer
 * @description
 * @author fex
 */

import React from 'react';
import Transition, {
  ENTERED,
  ENTERING,
  EXITING
} from 'react-transition-group/Transition';
import Portal from 'react-overlays/Portal';
import { Icon } from '../../../../components/icons';
import cx from 'classnames';
import { current, addModal, removeModal } from '../../../../components/ModalManager';
import { ClassNamesFn, themeable } from '../../../../theme';
import { noop, autobind, getScrollbarWidth } from '../../../../utils/helper';


export interface DrawerProps {
  className?: string;
  bodyClassName?: string;
  onHide: (e: any) => void;
  container: any;
  show?: boolean;
  disabled?: boolean;
  classPrefix: string;
  classnames: ClassNamesFn;
  onExited?: () => void;
  onEntered?: () => void;
}
export interface DrawerState { }
const fadeStyles: {
  [propName: string]: string;
} = {
  [ENTERING]: 'in',
  [ENTERED]: 'in',
  [EXITING]: 'out'
};
export class Drawer extends React.Component<DrawerProps, DrawerState> {
  static defaultProps: Pick<
    DrawerProps,
    'container'
  > = {
      container: document.body,
    };

  modalDom: HTMLElement;
  contentDom: HTMLElement;
  isRootClosed = false;

  componentDidMount() {
    if (this.props.show) {
      this.handleEntered();
    }

    document.body.addEventListener('click', this.handleRootClickCapture, true);
    document.body.addEventListener('click', this.handleRootClick);
  }

  componentDidUpdate(prevProps: DrawerProps) {
    // jest 里面没有触发 entered 导致后续的逻辑错误，
    // 所以直接 300 ms 后触发
    if (
      typeof jest !== 'undefined' &&
      prevProps.show !== this.props.show &&
      this.props.show
    ) {
      setTimeout(() => {
        this.handleEntered();
      }, 300);
    }
  }

  componentWillUnmount() {
    if (this.props.show) {

      this.handleExited();
    }

    document.body.removeEventListener('click', this.handleRootClick);
    document.body.removeEventListener(
      'click',
      this.handleRootClickCapture,
      true
    );
  }

  contentRef = (ref: any) => (this.contentDom = ref);

  handleEnter = () => {
    document.body.classList.add(`is-modalOpened`);
    if (
      window.innerWidth - document.documentElement.clientWidth > 0 ||
      document.body.scrollHeight > document.body.clientHeight
    ) {
      const scrollbarWidth = getScrollbarWidth();
      if (scrollbarWidth) {
        document.body.style.width = `calc(100% - ${scrollbarWidth}px)`;
      }
    }
  };

  handleEntered = () => {
    const onEntered = this.props.onEntered;
    onEntered && onEntered();
  };
  handleExited = () => {
    const onExited = this.props.onExited;
    document.activeElement && (document.activeElement as HTMLElement)?.blur?.();
    onExited && onExited();
    setTimeout(() => {
      if (!document.querySelector('.amis-dialog-widget')) {
        document.body.classList.remove(`is-modalOpened`);
        document.body.style.width = '';
      }
    }, 200);
  };

  modalRef = (ref: any) => {
    this.modalDom = ref;
    if (ref) {
      addModal(this);
      (ref as HTMLElement).classList.add(
        `${this.props.classPrefix}Modal--${current()}th`
      );
    } else {
      removeModal(this);
    }
  };

  @autobind
  handleRootClickCapture(e: MouseEvent) {
    const target = e.target as HTMLElement;
    const { classPrefix: ns } = this.props;
    const isLeftButton =
      (e.button === 1 && window.event !== null) || e.button === 0;

    this.isRootClosed = !!(
      isLeftButton &&
      target &&
      this.modalDom &&
      ((!this.modalDom.contains(target) && !target.closest('[role=dialog]')) ||
        (target.matches(`.${ns}Drawer-overlay`) &&
          target.parentElement === this.modalDom))
    ); // 干脆过滤掉来自弹框里面的点击
  }

  @autobind
  handleRootClick(e: MouseEvent) {
    const { onHide } = this.props;

    this.isRootClosed && !e.defaultPrevented && onHide(e);
  }

  render() {
    const {
      classPrefix: ns,
      className,
      children,
      container,
      show,
      onHide,
      disabled,
      bodyClassName
    } = this.props;


    return (
      <Transition
        mountOnEnter
        unmountOnExit
        in={show}
        timeout={300}
        onEnter={this.handleEnter}
        onExited={this.handleExited}
        onEntered={() => { this.handleEntered() }}
      >
        {(status: string) => (
          <Portal container={container}>
            <div
              ref={this.modalRef}
              role="lionChildView"
              className={cx(
                `amis-dialog-widget ${ns}lionChildView`,
                className,
                fadeStyles[status]
              )}
            // onClick={this.handleWidgetClick} // 其实不需要插件，直接写逻辑吧
            >
              <div
                ref={this.contentRef}
                className={cx(
                  `${ns}lionChildView-content`,
                  bodyClassName,
                )}
              >
                {children}
              </div>
            </div>
          </Portal>
        )}
      </Transition>
    );
  }
}

export default themeable(Drawer);
