import React from 'react'

import Menu, {
  type MenuActionProps,
  type MenuActionPropsBase,
  type MenuActionPropsWithToggle,
  type MenuProps as OriginalMenuProps,
} from '../Menu/Menu'
import Popover from '../Popover/Popover'
import { type PopoverProps } from '../Popover/Popover'
// Type for menu items that CANNOT have their own subMenu (i.e., items in a subMenu)
export type NoSubMenuAction = MenuActionProps & {
  subMenu?: never
  popoverSubMenuActions?: never
}

// Type for top-level menu items that CAN have a subMenu
// The subMenu itself will contain items of type NoSubMenuAction
export type DropdownAction = MenuActionProps & {
  subMenu?: MenuActionProps[]
}

export interface DropdownMenuProps {
  actions: DropdownAction[]
  trigger: React.JSX.Element
  popoverContentClassName?: string
  mainPopoverClassName?: string
  submenuPopoverClassName?: string
  reRenderView?: OriginalMenuProps['reRenderView']
  closeConfirmation?: OriginalMenuProps['closeConfirmation']
  popoverProps?: Omit<PopoverProps, 'children' | 'popoverContent'>
  /** Optional prop to add a test id to the DropdownMenu for QA testing */
  qaTestId?: string
}

interface MenuLevelContentProps {
  // Actions can be top-level (DropdownAction) or second-level (NoSubMenuAction)
  // Both are compatible with MenuActionProps for rendering the Menu itself.
  // The logic inside MenuLevelContent will determine if a subMenu can be opened.
  actions: Array<DropdownAction | NoSubMenuAction>
  closeMenuLevelAndParent?: () => void
  closeSelf: () => void
  depth: number
  baseProps: Pick<
    DropdownMenuProps,
    | 'reRenderView'
    | 'closeConfirmation'
    | 'popoverContentClassName'
    | 'submenuPopoverClassName'
    | 'qaTestId'
  >
}

const MenuLevelContent: React.FC<MenuLevelContentProps> = ({
  actions,
  closeSelf,
  depth,
  baseProps,
}) => {
  const menuActionsForMenuComponent: MenuActionProps[] = actions.map(
    (action) => {
      const {
        subMenu,
        callout: originalCallout,
        link,
        routerComponent,
        routerProp,
        toggle,
        csv,
        handleCsvAction: actionHandleCsvAction,
        setLoading: actionSetLoading,
        loading: actionLoading,
        text,
        icon,
        destructive,
        hasDivider,
        disabled,
        confirmation,
        qaTestId,
      } = action as DropdownAction

      const commonProps: MenuActionPropsBase = {
        destructive,
        hasDivider,
        disabled,
        confirmation,
        qaTestId,
      }

      if (depth === 0 && subMenu && subMenu.length > 0) {
        return {
          text: text!,
          icon,
          destructive: commonProps.destructive,
          hasDivider: commonProps.hasDivider,
          disabled: commonProps.disabled,
          subMenuTriggerActions: subMenu,
          qaTestId,
        } as MenuActionProps
      } else if (csv) {
        return {
          ...commonProps,
          csv,
          handleCsvAction: actionHandleCsvAction,
          setLoading: actionSetLoading,
          loading: actionLoading,
        } as MenuActionProps
      } else if (toggle) {
        return {
          ...commonProps,
          text,
          icon,
          toggle: {
            checked: toggle.checked,
            callout: toggle.callout,
          },
        } as MenuActionPropsWithToggle
      } else if (link) {
        return {
          ...commonProps,
          text,
          icon,
          link,
          routerComponent,
          routerProp,
          callout: originalCallout,
          secondaryContent: action.secondaryContent,
        } as MenuActionProps
      } else if (originalCallout) {
        return {
          ...commonProps,
          text,
          icon,
          callout: originalCallout,
          secondaryContent: action.secondaryContent,
        } as MenuActionProps
      } else if (confirmation) {
        return {
          ...commonProps,
          text,
          icon,
          confirmation,
          secondaryContent: action.secondaryContent,
        } as MenuActionProps
      }
      return {
        ...commonProps,
        text: text || '',
        icon,
        callout: closeSelf,
        secondaryContent: action.secondaryContent,
      } as MenuActionProps
    },
  )

  return (
    <div className={depth === 0 ? baseProps.popoverContentClassName || '' : ''}>
      <Menu
        actions={menuActionsForMenuComponent}
        close={closeSelf}
        reRenderView={baseProps.reRenderView}
        closeConfirmation={baseProps.closeConfirmation}
        qaTestId={baseProps.qaTestId}
      />
    </div>
  )
}

const DropdownMenu: React.FC<DropdownMenuProps> = ({
  actions,
  trigger,
  popoverContentClassName,
  mainPopoverClassName,
  submenuPopoverClassName,
  reRenderView,
  closeConfirmation,
  popoverProps,
  qaTestId = 'dropdown-menu',
}) => {
  return (
    <Popover
      {...popoverProps}
      noPadding
      popoverContent={({ setVisible }) => (
        <MenuLevelContent
          actions={actions}
          closeSelf={() => setVisible(false)}
          closeMenuLevelAndParent={() => setVisible(false)}
          depth={0}
          baseProps={{
            reRenderView,
            closeConfirmation,
            popoverContentClassName,
            submenuPopoverClassName,
            qaTestId,
          }}
        />
      )}
      className={mainPopoverClassName}
      qaTestId={qaTestId}
    >
      {({ setVisible, visible }) => {
        return React.cloneElement(trigger, {
          onClick: (e: React.MouseEvent<HTMLElement>) => {
            setVisible((v: boolean) => !v)
            trigger.props.onClick?.(e)
          },
          'aria-haspopup': 'true',
          'aria-expanded': visible,
        })
      }}
    </Popover>
  )
}

export default DropdownMenu
