import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { getDocument } from '@atlaskit/browser-apis';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
var hasEnabledItems = function hasEnabledItems(list) {
  return list.some(function (item) {
    return item.getAttribute('aria-disabled') !== 'true';
  });
};

/**
 * This component is a wrapper of vertical menus which listens to keydown events of children
 * and handles up/down arrow key navigation
 */
export var MenuArrowKeyNavigationProvider = function MenuArrowKeyNavigationProvider(_ref) {
  var children = _ref.children,
    handleClose = _ref.handleClose,
    disableArrowKeyNavigation = _ref.disableArrowKeyNavigation,
    keyDownHandlerContext = _ref.keyDownHandlerContext,
    closeOnTab = _ref.closeOnTab,
    onSelection = _ref.onSelection,
    editorRef = _ref.editorRef,
    popupsMountPoint = _ref.popupsMountPoint,
    disableCloseOnArrowClick = _ref.disableCloseOnArrowClick;
  var wrapperRef = useRef(null);
  var _useState = useState(-1),
    _useState2 = _slicedToArray(_useState, 2),
    currentSelectedItemIndex = _useState2[0],
    setCurrentSelectedItemIndex = _useState2[1];
  var element = popupsMountPoint ? [popupsMountPoint, editorRef.current] : [editorRef.current];
  var _useState3 = useState(element),
    _useState4 = _slicedToArray(_useState3, 1),
    listenerTargetElement = _useState4[0];
  var getCurrentIndex = useCallback(function (list) {
    var _getDocument;
    if (!expValEquals('platform_editor_layout_column_menu', 'isEnabled', true)) {
      return currentSelectedItemIndex;
    }
    var activeElement = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement;
    if (!(activeElement instanceof HTMLElement)) {
      return currentSelectedItemIndex;
    }
    var activeElementIndex = list.indexOf(activeElement);
    return activeElementIndex >= 0 ? activeElementIndex : currentSelectedItemIndex;
  }, [currentSelectedItemIndex]);
  var incrementIndex = useCallback(function (list) {
    var currentIndex = getCurrentIndex(list);
    var nextIndex = (currentIndex + 1) % list.length;
    // Skips disabled items. Previously this function relied on a list of enabled elements which caused a
    // difference between currentIndex and the item index in the menu.
    while (nextIndex !== currentIndex && list[nextIndex].getAttribute('aria-disabled') === 'true') {
      nextIndex = (nextIndex + 1) % list.length;
    }
    setCurrentSelectedItemIndex(nextIndex);
    return nextIndex;
  }, [getCurrentIndex]);
  var decrementIndex = useCallback(function (list) {
    var currentIndex = getCurrentIndex(list);
    var nextIndex = (list.length + currentIndex - 1) % list.length;
    while (nextIndex !== currentIndex && list[nextIndex].getAttribute('aria-disabled') === 'true') {
      nextIndex = (list.length + nextIndex - 1) % list.length;
    }
    setCurrentSelectedItemIndex(nextIndex);
    return nextIndex;
  }, [getCurrentIndex]);

  // this useEffect uses onSelection in it's dependency list which gets
  // changed as a result of the dropdown menu getting re-rendered in it's
  // parent component. Note that if onSelection gets updated to useMemo
  // this will no longer work.
  useEffect(function () {
    var currentIndex = currentSelectedItemIndex;
    var list = getFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
    var currentElement = list[currentIndex];

    // eslint-disable-next-line @atlassian/perf-linting/no-chain-state-updates -- Ignored via go/ees017 (to be fixed)
    if (currentElement && currentElement.getAttribute('aria-disabled') === 'true') {
      var _list$focusIndex;
      // eslint-disable-next-line @atlassian/perf-linting/no-chain-state-updates -- Ignored via go/ees017 (to be fixed)
      var focusIndex = incrementIndex(list);
      // eslint-disable-next-line @atlassian/perf-linting/no-chain-state-updates -- Ignored via go/ees017 (to be fixed)
      (_list$focusIndex = list[focusIndex]) === null || _list$focusIndex === void 0 || _list$focusIndex.focus();
    }
  }, [currentSelectedItemIndex, onSelection, incrementIndex, decrementIndex]);
  useLayoutEffect(function () {
    // Backwards compatible behaviour:
    // - `true` disables all key handling (no listeners attached)
    // - a function is evaluated per event inside the handler
    if (disableArrowKeyNavigation === true) {
      return;
    }

    /**
     * To handle the key events on the list
     * @param event
     */
    var handleKeyDown = function handleKeyDown(event) {
      var _wrapperRef$current;
      if (typeof disableArrowKeyNavigation === 'function' && disableArrowKeyNavigation(event)) {
        return;
      }
      var targetElement = event.target;

      // Tab key on menu items can be handled in the parent components of dropdown menus with KeydownHandlerContext
      if (event.key === 'Tab' && closeOnTab) {
        // Ignored via go/ees005
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        handleClose(event);
        keyDownHandlerContext === null || keyDownHandlerContext === void 0 || keyDownHandlerContext.handleTab();
        return;
      }

      // To trap the focus inside the toolbar using left and right arrow keys
      var focusableElements = getFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
      if (!focusableElements || (focusableElements === null || focusableElements === void 0 ? void 0 : focusableElements.length) === 0) {
        return;
      }
      if (targetElement instanceof HTMLElement && !((_wrapperRef$current = wrapperRef.current) !== null && _wrapperRef$current !== void 0 && _wrapperRef$current.contains(targetElement))) {
        setCurrentSelectedItemIndex(-1);
      }
      switch (event.key) {
        case 'ArrowDown':
          {
            if (hasEnabledItems(focusableElements)) {
              var _focusableElements$fo;
              var focusIndex = incrementIndex(focusableElements);
              (_focusableElements$fo = focusableElements[focusIndex]) === null || _focusableElements$fo === void 0 || _focusableElements$fo.focus();
              event.preventDefault();
            }
            break;
          }
        case 'ArrowUp':
          {
            if (hasEnabledItems(focusableElements)) {
              var _focusableElements$_f;
              var _focusIndex = decrementIndex(focusableElements);
              (_focusableElements$_f = focusableElements[_focusIndex]) === null || _focusableElements$_f === void 0 || _focusableElements$_f.focus();
              event.preventDefault();
            }
            break;
          }

        // ArrowLeft/Right on the menu should close the menus
        // then logic to retain the focus can be handled in the parent components with KeydownHandlerContext
        case 'ArrowLeft':
          if (targetElement instanceof HTMLElement && !targetElement.closest('.custom-key-handler-wrapper')) {
            return;
          }
          if (!disableCloseOnArrowClick) {
            // Ignored via go/ees005
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            handleClose(event);
          }
          if (targetElement instanceof HTMLElement && !targetElement.closest('[data-testid="editor-floating-toolbar"]')) {
            keyDownHandlerContext === null || keyDownHandlerContext === void 0 || keyDownHandlerContext.handleArrowLeft();
          }
          break;
        case 'ArrowRight':
          if (targetElement instanceof HTMLElement && !targetElement.closest('.custom-key-handler-wrapper')) {
            return;
          }
          if (!disableCloseOnArrowClick) {
            // Ignored via go/ees005
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            handleClose(event);
          }
          if (targetElement instanceof HTMLElement && !targetElement.closest('[data-testid="editor-floating-toolbar"]')) {
            keyDownHandlerContext === null || keyDownHandlerContext === void 0 || keyDownHandlerContext.handleArrowRight();
          }
          break;
        case 'Escape':
          // Ignored via go/ees005
          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
          handleClose(event);
          break;
        case 'Enter':
          if (typeof onSelection === 'function') {
            onSelection(currentSelectedItemIndex);
          }
          break;
        default:
          return;
      }
    };
    listenerTargetElement && listenerTargetElement.forEach(function (elem) {
      // Ignored via go/ees005
      // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
      elem && elem.addEventListener('keydown', handleKeyDown);
    });
    return function () {
      listenerTargetElement && listenerTargetElement.forEach(function (elem) {
        // Ignored via go/ees005
        // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
        elem && elem.removeEventListener('keydown', handleKeyDown);
      });
    };
  }, [currentSelectedItemIndex, wrapperRef, handleClose, disableArrowKeyNavigation, keyDownHandlerContext, closeOnTab, onSelection, incrementIndex, decrementIndex, listenerTargetElement, disableCloseOnArrowClick]);
  return /*#__PURE__*/React.createElement("div", {
    // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
    className: "menu-key-handler-wrapper custom-key-handler-wrapper",
    ref: wrapperRef
  }, children);
};
function getFocusableElements(rootNode) {
  if (!rootNode) {
    return [];
  }
  var focusableModalElements = rootNode.querySelectorAll('a[href], button:not([disabled]), textarea, input, select, div[tabindex="-1"]') || [];
  return Array.from(focusableModalElements);
}