import _defineProperty from "@babel/runtime/helpers/defineProperty";
// Copyright 1999-2023. Plesk International GmbH. All rights reserved.

import { findDOMNode } from 'react-dom';
import classNames from 'classnames';
import Measure from 'react-measure';
import { CLS_PREFIX, Z_INDEX_POPOVER } from '../../constants';
import Popper from '../Popper';
import Button from '../Button';
import Heading from '../Heading';
import AutoClosable from '../AutoClosable';
import { isLikeText } from '../Translate';
import { wrapFunction } from '../utils';
import OnDarkContext from '../OnDarkContext';
import FocusTrap from '../FocusTrap';
import { cloneElement, Component, createRef } from 'react';
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
const PLACEMENT_MAP = {
  'top-left': 'top-end',
  'top-right': 'top-start',
  'right-top': 'right-end',
  'right-bottom': 'right-start',
  'bottom-left': 'bottom-end',
  'bottom-right': 'bottom-start',
  'left-top': 'left-end',
  'left-bottom': 'left-start',
  top: 'top',
  right: 'right',
  bottom: 'bottom',
  left: 'left',
  auto: 'auto'
};
const ARROW_HEIGHT = 26;
const isControlled = props => props.visible !== null;
const normalize = value => String(Number(value)) === String(value) ? `${value}px` : value;
/**
 * `Popover` component is non-modal pop-up window used for providing additional information
 * for an interface element. It also may contain Form with few fields or any other small content.
 * @since 0.0.42
 */
class Popover extends Component {
  constructor() {
    super(...arguments);
    _defineProperty(this, "state", {
      show: this.props.defaultVisible,
      arrowInHeader: false
    });
    _defineProperty(this, "contentRef", /*#__PURE__*/createRef());
    _defineProperty(this, "targetRef", /*#__PURE__*/createRef());
    _defineProperty(this, "prevFocusElement", void 0);
    _defineProperty(this, "popperData", void 0);
    _defineProperty(this, "headerBounds", void 0);
    _defineProperty(this, "checkArrowPosition", () => {
      const {
        title
      } = this.props;
      const {
        show,
        arrowInHeader
      } = this.state;
      if (!show || !this.popperData) {
        return;
      }
      const {
        actualPlacement,
        arrowStyle
      } = this.popperData;
      const top = parseInt(arrowStyle?.top || '');
      const [direction] = actualPlacement?.split('-') || [];
      let newArrowInHeader = false;
      const directionBottomOrPopoverLowEnough = direction === 'bottom' || top !== null && this.headerBounds && top < this.headerBounds.height - ARROW_HEIGHT / 2;
      const rightDirection = direction !== 'top' && directionBottomOrPopoverLowEnough;
      if (title && this.headerBounds && rightDirection) {
        newArrowInHeader = true;
      }
      if (arrowInHeader !== newArrowInHeader) {
        this.setState({
          arrowInHeader: newArrowInHeader
        });
      }
    });
    _defineProperty(this, "hotkeyHandler", e => {
      if (!e.isDefaultPrevented() && e.key === 'Escape') {
        this.handleClose();
        e.preventDefault();
      }
    });
    _defineProperty(this, "handleTargetClick", e => {
      const {
        show
      } = this.state;
      const {
        canCloseOnOutsideClick
      } = this.props;
      if (show && !canCloseOnOutsideClick) {
        return;
      }
      this.targetRef.current = e.currentTarget;
      this.setState(prevState => ({
        show: !prevState.show
      }));
    });
    _defineProperty(this, "handleClose", () => {
      const {
        show
      } = this.state;
      if (!show) {
        return;
      }
      const {
        onClose,
        canCloseOnEscapePress,
        autoFocus
      } = this.props;
      const isNeedFocus = autoFocus && canCloseOnEscapePress && this.prevFocusElement && (!document.activeElement || this.contentRef.current?.contains(document.activeElement));
      if (onClose) {
        onClose();
      } else {
        this.setState({
          show: false
        });
      }
      if (isNeedFocus) {
        this.prevFocusElement?.focus();
      }
    });
    _defineProperty(this, "handleHeaderResize", contentRect => {
      this.headerBounds = contentRect.bounds;
      this.checkArrowPosition();
    });
    _defineProperty(this, "handlePopperUpdate", popperData => {
      this.popperData = popperData;
      this.checkArrowPosition();
    });
    _defineProperty(this, "getIgnoreNodes", () => {
      const {
        targetRef
      } = this.props;
      if (targetRef || this.targetRef.current) {
        return [targetRef, this.targetRef];
      }
      return [findDOMNode(this)];
    });
  }
  static getDerivedStateFromProps(props, state) {
    return {
      show: isControlled(props) ? props.visible : state.show
    };
  }
  componentDidUpdate(_, prevState) {
    const {
      canCloseOnEscapePress,
      autoFocus
    } = this.props;
    const {
      show
    } = this.state;
    if (autoFocus && canCloseOnEscapePress && !prevState.show && show) {
      setTimeout(() => this.focus(), 0);
    }
  }
  focus() {
    if (this.contentRef.current === null || document.activeElement === null || !this.state.show) {
      return;
    }
    this.prevFocusElement = document.activeElement;
    const isFocusOutside = !this.contentRef.current.contains(document.activeElement);
    if (isFocusOutside) {
      const autofocusElement = this.contentRef.current.querySelector('[autofocus]');
      if (autofocusElement !== null) {
        autofocusElement.focus();
      } else if (this.contentRef.current) {
        this.contentRef.current.focus();
      }
    }
  }
  render() {
    const {
      baseClassName,
      className,
      visible,
      defaultVisible,
      title,
      placement,
      canCloseOnOutsideClick,
      canCloseOnEscapePress,
      target,
      targetRef,
      intent,
      wide,
      width,
      height,
      extra,
      onClose,
      children,
      ...props
    } = this.props;
    const {
      show,
      arrowInHeader
    } = this.state;
    let behavior;
    if (placement !== 'auto') {
      const [direction] = placement?.split('-') || [];
      if (direction === 'top') {
        behavior = ['top', 'bottom', 'right', 'left'];
      } else if (direction === 'right') {
        behavior = ['right', 'left', 'bottom', 'top'];
      } else if (direction === 'bottom') {
        behavior = ['bottom', 'top', 'left', 'right'];
      } else if (direction === 'left') {
        behavior = ['left', 'right', 'top', 'bottom'];
      }
    }
    const close = /*#__PURE__*/_jsx(Button, {
      className: classNames(`${baseClassName}__close`, title && `${baseClassName}__close--heading`),
      onClick: this.handleClose,
      ghost: true,
      icon: {
        name: 'cross-mark',
        size: title ? 16 : 12
      }
    });
    const heading = title && /*#__PURE__*/_jsx(Measure, {
      onResize: this.handleHeaderResize,
      bounds: true,
      children: _ref => {
        let {
          measureRef
        } = _ref;
        return /*#__PURE__*/_jsxs("div", {
          ref: measureRef,
          className: `${baseClassName}__heading`,
          children: [isLikeText(title) ? /*#__PURE__*/_jsx(Heading, {
            level: 5,
            className: `${baseClassName}__title`,
            children: title
          }) : title, /*#__PURE__*/_jsxs("div", {
            className: `${baseClassName}__extra`,
            children: [extra, close]
          })]
        });
      }
    });
    const trigger = isControlled(this.props) ? target : /*#__PURE__*/cloneElement(target, {
      className: classNames(target.props.className, `${baseClassName}__target`),
      onClick: wrapFunction(target.props.onClick, this.handleTargetClick)
    });
    const popperPlacement = placement ? PLACEMENT_MAP[placement] : undefined;
    let wrapperStyle;
    if (height) {
      wrapperStyle = {
        height: normalize(height)
      };
    }
    const content = /*#__PURE__*/_jsxs(FocusTrap, {
      ref: this.contentRef,
      onKeyUp: canCloseOnEscapePress && show ? this.hotkeyHandler : undefined,
      className: `${baseClassName}__inner`,
      style: wrapperStyle,
      children: [height ? heading : heading || close, /*#__PURE__*/_jsx("div", {
        className: `${baseClassName}__content`,
        children: /*#__PURE__*/_jsx("div", {
          className: `${baseClassName}__content-inner`,
          children: typeof children === 'function' ? children({
            onClose: this.handleClose
          }) : children
        })
      })]
    });
    return /*#__PURE__*/_jsx(Popper, {
      target: trigger,
      targetRef: targetRef ? targetRef : this.targetRef,
      arrow: /*#__PURE__*/_jsx("span", {
        className: classNames(`${baseClassName}__arrow`, arrowInHeader && `${baseClassName}__arrow--heading`)
      }),
      placement: popperPlacement,
      onUpdate: this.handlePopperUpdate,
      className: classNames({
        [`${baseClassName}--heading`]: title,
        [`${baseClassName}--${intent}`]: intent,
        [`${baseClassName}--wide`]: wide || width,
        [`${baseClassName}--width-${width}`]: width,
        [`${baseClassName}--on-dark`]: this.context === true
      }, className),
      baseClassName: baseClassName,
      behavior: behavior,
      zIndex: Z_INDEX_POPOVER,
      show: show,
      ...props,
      children: canCloseOnOutsideClick ? /*#__PURE__*/_jsx(AutoClosable, {
        onClose: this.handleClose,
        ignoreNodes: this.getIgnoreNodes,
        nodeRef: this.contentRef,
        children: content
      }) : content
    });
  }
}
// eslint-disable-next-line react/sort-comp
_defineProperty(Popover, "contextType", OnDarkContext);
_defineProperty(Popover, "defaultProps", {
  visible: null,
  defaultVisible: false,
  title: undefined,
  onClose: undefined,
  placement: 'auto',
  canCloseOnOutsideClick: true,
  canCloseOnEscapePress: true,
  children: undefined,
  intent: undefined,
  wide: undefined,
  width: undefined,
  height: undefined,
  extra: undefined,
  className: undefined,
  baseClassName: `${CLS_PREFIX}popover`,
  boundariesElement: undefined,
  autoFocus: true,
  targetRef: undefined
});
export default Popover;