import { useRef, useState } from 'react';
import { EnrichedMenuDataItem } from '../types.js';
import { ChevronIcon } from './Chevron/index.js';
import { HandleKeyDownProps, MenuItemProps } from './types.js';
import styles from './index.module.scss';

const MenuItem = ({
  item,
  level,
  maxDepth,
  addArrows = false,
  className = '',
  useNavigationControls = false,
  style = {},
}: MenuItemProps) => {
  const itemRef = useRef<HTMLLIElement>(null);
  const linkRef = useRef<HTMLAnchorElement>(null);
  const [isSubmenuOpen, setIsSubmenuOpen] = useState(false);
  const hasUrl = Boolean(item?.url && item.url.trim() !== '');
  const hasChildren = Boolean(item?.children?.length);
  const shouldShowChildren = maxDepth
    ? hasChildren && level < maxDepth
    : hasChildren;

  const focusElement = (element: Element | null | undefined) => {
    if (element instanceof HTMLElement) {
      element.focus();
    }
  };

  const focusNextSibling = () => {
    const nextSibling = itemRef.current?.nextElementSibling;
    if (nextSibling) {
      focusElement(nextSibling);
    } else {
      focusFirstSibling();
    }
  };

  const focusPreviousSibling = () => {
    const previousSibling = itemRef.current?.previousElementSibling;
    if (previousSibling) {
      focusElement(previousSibling);
    } else {
      focusLastSibling();
    }
  };

  const focusParentItem = () => {
    const parentItem = itemRef.current?.parentElement?.closest('li');
    focusElement(parentItem);
  };

  const focusParentNav = () => {
    const parentNav = itemRef.current?.closest('nav');
    focusElement(parentNav);
  };

  const focusFirstSibling = () => {
    const parent = itemRef.current?.parentElement;
    focusElement(parent?.firstElementChild);
  };

  const focusLastSibling = () => {
    const parent = itemRef.current?.parentElement;
    focusElement(parent?.lastElementChild);
  };

  const openSubmenu = () => {
    setIsSubmenuOpen(true);

    requestAnimationFrame(() => {
      const firstChild = itemRef.current?.querySelector('ul > li');
      focusElement(firstChild);
    });
  };

  const closeSubmenu = () => {
    setIsSubmenuOpen(false);
  };

  const activateLink = () => {
    linkRef.current?.click();
  };

  const navigateToSiblingAndCloseSubmenu = (direction: 'next' | 'previous') => {
    closeSubmenu();
    if (direction === 'next') {
      focusNextSibling();
    } else {
      focusPreviousSibling();
    }
  };

  const returnToParentAndCloseSubmenu = () => {
    focusParentItem();
    closeSubmenu();
  };

  const exitMenuAndCloseSubmenu = () => {
    closeSubmenu();
    itemRef.current?.blur();
  };

  const handleKeyDown = ({ event, menuLevel }: HandleKeyDownProps) => {
    const isTopLevel = menuLevel === 1;

    event.stopPropagation();

    switch (event.key) {
      case 'ArrowRight':
        event.preventDefault();
        if (isTopLevel) {
          navigateToSiblingAndCloseSubmenu('next');
        } else if (shouldShowChildren) {
          openSubmenu();
        }
        break;

      case 'ArrowLeft':
        event.preventDefault();
        if (isTopLevel) {
          navigateToSiblingAndCloseSubmenu('previous');
        } else {
          returnToParentAndCloseSubmenu();
        }
        break;

      case 'ArrowDown':
        event.preventDefault();
        if (isTopLevel && shouldShowChildren) {
          openSubmenu();
        } else {
          focusNextSibling();
        }
        break;

      case 'ArrowUp':
        event.preventDefault();
        if (isTopLevel) {
          focusParentNav();
        } else {
          focusPreviousSibling();
        }
        break;

      case 'Enter':
      case ' ':
        event.preventDefault();
        activateLink();
        break;

      case 'Escape':
        event.preventDefault();
        if (isTopLevel) {
          exitMenuAndCloseSubmenu();
        } else {
          returnToParentAndCloseSubmenu();
        }
        break;

      case 'Home':
        event.preventDefault();
        focusFirstSibling();
        break;

      case 'End':
        event.preventDefault();
        focusLastSibling();
        break;

      default:
        break;
    }
  };

  const renderContent = () => {
    if (hasUrl) {
      const linkAttributes =
        item.linkTarget === '_blank'
          ? { target: '_blank', rel: 'noopener noreferrer' }
          : {};

      return (
        <a
          ref={linkRef}
          href={item.url!}
          className={styles.link}
          tabIndex={-1}
          {...linkAttributes}
        >
          {item.label}
          {shouldShowChildren && addArrows && <ChevronIcon />}
        </a>
      );
    }

    return (
      <span className={styles.link}>
        {item.label}
        {shouldShowChildren && addArrows && <ChevronIcon />}
      </span>
    );
  };

  const handleBlur = (event: React.FocusEvent) => {
    const relatedTarget = event.relatedTarget as Node | null;

    // Keep submenu open if focus is moving to a child (drilling down)
    if (
      relatedTarget &&
      itemRef.current?.contains(relatedTarget) &&
      relatedTarget !== itemRef.current
    ) {
      return;
    }

    // Close submenu when moving away (up to parent, sideways to sibling, or outside)
    setIsSubmenuOpen(false);
  };

  const itemStyle: React.CSSProperties & Record<`--hs-${string}`, number> = {
    ...style,
    '--hs-menuItem-level': level,
  };

  return (
    <li
      ref={itemRef}
      className={className}
      style={itemStyle}
      data-level={level}
      data-submenu-open={
        useNavigationControls ? (isSubmenuOpen ? 'true' : 'false') : undefined
      }
      tabIndex={useNavigationControls ? -1 : 0}
      role="menuitem"
      aria-expanded={
        useNavigationControls && shouldShowChildren ? isSubmenuOpen : undefined
      }
      {...(useNavigationControls && {
        onKeyDown: event => handleKeyDown({ event, menuLevel: level }),
        onBlur: handleBlur,
      })}
    >
      {renderContent()}

      {shouldShowChildren && (
        <ul>
          {item.children.map((child: EnrichedMenuDataItem) => (
            <MenuItem
              key={child._id}
              item={child}
              level={level + 1}
              maxDepth={maxDepth}
              addArrows={addArrows}
              useNavigationControls={useNavigationControls}
            />
          ))}
        </ul>
      )}
    </li>
  );
};

export default MenuItem;
