import React, { useMemo } from 'react';
import { Menu as HeadlessMenu } from '@headlessui/react';
import { clsx } from 'clsx';

import { applyClassName } from '../utils/misc';
import { forwardRef } from '../utils/react';
import { MenuItem, MenuItemButton, MenuItemIcon, MenuItemProps } from '../menu';
import * as css from './dropdown-menu-item.css';

/*-- Types --*/

type HeadlessMenuItemContext = {
  active: boolean;
  disabled: boolean;
};

type HeadlessMenuItemProps = {
  children?:
    | React.ReactNode
    | ((context: HeadlessMenuItemContext) => React.ReactNode);
  className?: string | ((context: HeadlessMenuItemContext) => string);
};

export interface DropdownMenuItemProps
  extends MenuItemProps,
    Omit<HeadlessMenuItemProps, 'className'> {
  disabled?: boolean;
  icon?:
    | React.ReactNode
    | ((context: HeadlessMenuItemContext) => React.ReactNode);
  className?:
    | HeadlessMenuItemProps['className']
    | {
        base?: HeadlessMenuItemProps['className'];
        button?: HeadlessMenuItemProps['className'];
        icon?: HeadlessMenuItemProps['className'];
        body?: HeadlessMenuItemProps['className'];
      };
}

/*-- Main --*/

export const DropdownMenuItem = forwardRef<'li', DropdownMenuItemProps>(
  function DropdownMenuItem(
    { children, className, disabled, icon, ...rest },
    ref,
  ) {
    const cn = useMemo(() => {
      const classNameObject =
        typeof className === 'string' || typeof className === 'function'
          ? { base: className }
          : className || {};

      return {
        base: (itemContext: HeadlessMenuItemContext) =>
          applyClassName(classNameObject.base, itemContext),
        button: (itemContext: HeadlessMenuItemContext) =>
          clsx(applyClassName(classNameObject.button, itemContext), {
            [css.itemFocused]: itemContext.active,
          }),
        body: (itemContext: HeadlessMenuItemContext) =>
          applyClassName(classNameObject.body, itemContext),
        icon: (itemContext: HeadlessMenuItemContext) =>
          applyClassName(classNameObject.icon, itemContext),
      };
    }, [className]);

    return (
      <HeadlessMenu.Item disabled={disabled}>
        {itemContext => (
          <MenuItem ref={ref} className={cn.base(itemContext)} {...rest}>
            <MenuItemButton
              className={cn.button(itemContext)}
              disabled={disabled}
            >
              {icon && (
                <MenuItemIcon className={cn.icon(itemContext)}>
                  {typeof icon === 'function' ? icon(itemContext) : icon}
                </MenuItemIcon>
              )}

              <span className={cn.body(itemContext)}>
                {typeof children === 'function'
                  ? children(itemContext)
                  : children}
              </span>
            </MenuItemButton>
          </MenuItem>
        )}
      </HeadlessMenu.Item>
    );
  },
);
