import { Placement } from '@popperjs/core';
import clsx from 'clsx';
import React, { Ref, useState } from 'react';
import { createPortal } from 'react-dom';
import { usePopper } from 'react-popper';
import { useExpand } from '../../hooks/useExpand/useExpand';
import { Actions, ActionsProps } from '../Actions';
import { Button, ButtonContext } from '../Buttons';
import { IconName } from '../Icons';
import classes from './InlineMenu.scss';

export interface InlineMenuProps extends ActionsProps {
  /** Additional CSS class for the action container */
  className?: string;
  /** Additional CSS class for the button */
  buttonClassName?: string;
  /** Move along the reference element default(0) */
  offsetSkidding?: number;
  /** Distance to the reference element default(6) */
  offsetDistance?: number;
  /** Default placement can be changed with this optional property (default: 'top') */
  placement?: Placement;
  /** Applies white background with opacity 70% */
  addBackgroundOpacity?: boolean;
  /**  */
  showArrow?: boolean;
  buttonIcon?: IconName;
  buttonContext?: ButtonContext;
  onButtonClicked?: (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
  ) => void;
}

/**
 * Renders an actions context menu.
 * @example
 * const [referenceElement, setReferenceElement] = useState<HTMLElement>();
 * <div ref={setReferenceElement as React.LegacyRef<HTMLDivElement>}>
 *   <InlineMenu
 *   referenceElement={referenceElement}
 *   actions={[{ label: 'Action Label', onActionSelected={actionSelectedHandler} }]}
 *   />
 * </div>
 */
export const InlineMenu: React.FC<InlineMenuProps> = ({
  showArrow = true,
  offsetSkidding = 0,
  offsetDistance = showArrow ? 6 : 0,
  placement = 'top',
  addBackgroundOpacity = false,
  className,
  buttonClassName,
  buttonIcon = IconName.MidlineEllipsis,
  buttonContext,
  onButtonClicked,
  onActionClick,
  ...rest
}) => {
  const [popperElement, setPopperElement] = useState<HTMLDivElement>();
  const [arrowElement, setArrowElement] = useState<HTMLDivElement>();
  const [referenceElement, setReferenceElement] = useState<HTMLElement>();
  const { isExpanded, toggleExpanded, collapse } = useExpand(false);
  let onBlurTimeout: NodeJS.Timeout;

  const { styles, attributes } = usePopper(referenceElement, popperElement, {
    modifiers: [
      {
        name: 'arrow',
        options: { element: arrowElement },
      },
      {
        name: 'offset',
        options: {
          offset: [offsetSkidding, offsetDistance],
        },
      },
    ],
    placement,
  });

  return (
    <>
      <Button
        ref={setReferenceElement as Ref<HTMLButtonElement>}
        type="button"
        icon={buttonIcon}
        onButtonClicked={(e) => {
          toggleExpanded();
          onButtonClicked?.(e);
        }}
        onBlur={() => {
          onBlurTimeout = global.setTimeout(() => collapse(), 250);
        }}
        buttonContext={buttonContext}
        className={clsx(
          { [classes.buttonDefault]: !buttonContext && !addBackgroundOpacity },
          {
            [classes.buttonDefaultOpacity]:
              !buttonContext && addBackgroundOpacity,
          },
          {
            [classes.buttonSelected]: !buttonContext && isExpanded,
          },
          buttonClassName,
        )}
        dataTestId="inline-menu-button"
      />
      {isExpanded &&
        createPortal(
          <div
            tabIndex={-1}
            className={clsx(classes.container, 'sub-menu-container', className)}
            ref={setPopperElement as React.LegacyRef<HTMLDivElement>}
            style={styles.popper}
            {...attributes.popper}
            onBlur={() => {
              onBlurTimeout = global.setTimeout(() => collapse(), 250);
            }}
            onContextMenu={() => {
              clearTimeout(onBlurTimeout);
            }}
            data-test-id="inline-menu"
          >
            <Actions
              {...rest}
              onActionClick={(e, action) => {
                if (
                  action.confirmationMode &&
                  action.confirmationMode !== 'None'
                ) {
                  clearTimeout(onBlurTimeout);
                } else {
                  onBlurTimeout = global.setTimeout(() => collapse(), 250);
                }
                onActionClick?.(e, action);
              }}
            />
            <div
              ref={setArrowElement as React.LegacyRef<HTMLDivElement>}
              className={classes.arrow}
              // style={styles.arrow}
              style={{
                ...styles.arrow,
                display: showArrow ? 'inherit' : 'none',
              }}
            />
          </div>,
          document.body,
        )}
    </>
  );
};
