import React from 'react';

import {createElemPropsHook, useMountLayout} from '@workday/canvas-kit-react/common';

import {orientationKeyMap} from './keyUtils';
import {isCursor} from './useCursorListModel';
import {useListModel} from './useListModel';

/**
 * This elemProps hook resets the cursor when the list looses focus. By default,
 * [useListItemRovingFocus](#use-list-item-roving-focus) will leave the last focused item as the
 * focusable item in the list. Sometimes it is desireable to reset the cursor to the last selected
 * item. For example, `Tabs.Item` uses this hook to reset the tab stop to the currently selected tab.
 *
 * ```ts
 * const useMyItem = composeHooks(
 *   useListResetCursorOnBlur, // adds the cursor reset to selected for roving tabindex
 *   useListItemRovingFocus,
 *   useListItemRegister
 * );
```
 */
export const useListResetCursorOnBlur = createElemPropsHook(useListModel)(({state, events}) => {
  const programmaticFocusRef = React.useRef(false);
  const requestAnimationFrameRef = React.useRef(0);

  useMountLayout(() => {
    return () => {
      // Cancelling the animation frame prevents React unmount errors
      cancelAnimationFrame(requestAnimationFrameRef.current);
    };
  });

  return {
    onKeyDown(event: React.KeyboardEvent) {
      // Programmatic focus only on any focus change via keyboard
      if (Object.keys(orientationKeyMap[state.orientation]).indexOf(event.key) !== -1) {
        programmaticFocusRef.current = true;
      }
    },
    onFocus() {
      programmaticFocusRef.current = false;
    },
    onBlur() {
      if (!programmaticFocusRef.current) {
        // use an animation frame to wait for any other model changes that may happen on a blur
        requestAnimationFrameRef.current = requestAnimationFrame(() => {
          if (!isCursor(state, state.selectedIds[0])) {
            events.goTo({id: state.selectedIds[0]});
          }
        });
      }
    },
  };
});
