"use client";

import type { Ref, RefAttributes, ReactNode, ReactElement } from "react";
import { Children, isValidElement, cloneElement, useState } from "react";
import useDropdownMenu from "react-accessible-dropdown-menu-hook";
import classNames from "classnames/dedupe";
import type { DOMProps } from "../../types/dom";

import { Button } from "../Button";
import "./DropdownMenu.css";

export type DropdownMenuElementType = HTMLElement;

export interface DropdownMenuProps
  extends DOMProps, RefAttributes<DropdownMenuElementType> {
  children?: ReactNode;
  /** Custom class name for setting specific CSS */
  className?: string;
  elementType?: React.ElementType;
  label?: string;
  trigger?: ReactElement;
}

export type DropdownMenuRef = Ref<DropdownMenuElementType>;

type ChildClickProps = {
  onClick?: () => void;
};

const DropdownMenu = ({ ref, ...props }: DropdownMenuProps) => {
  const {
    elementType: Element = "nav",
    trigger,
    label = "Menu",
    children,
    ...otherProps
  } = props;
  const [activeId, setActiveId] = useState<number | null>(null);
  const numberOfItems = Children.count(children);
  const {
    buttonProps,
    itemProps,
    isOpen: open,
    setIsOpen,
  } = useDropdownMenu(numberOfItems);

  const classes = classNames(
    "mobius",
    "mobius-dropdown-menu",
    otherProps.className,
  );
  const triggerClasses = classNames("mobius", "mobius-dropdown-menu__trigger");
  const listClasses = classNames("mobius", "mobius-dropdown-menu__list", {
    "--is-open": open,
  });

  const handleChildClick = ({ onClick }: ChildClickProps, index: number) => {
    setActiveId(index);
    setIsOpen(false);

    if (onClick) {
      onClick();
    }
  };

  return (
    <Element ref={ref} {...otherProps} className={classes}>
      {trigger ? (
        cloneElement(trigger, {
          className: triggerClasses,
          open,
          label,
          ...buttonProps,
        } as Record<string, unknown>)
      ) : (
        <Button className={triggerClasses} {...buttonProps}>
          {label}
        </Button>
      )}
      <ul className={listClasses} role="menu">
        {Children.map(children, (child, index) => {
          if (isValidElement(child)) {
            // DropdownMenu items accept onClick and active props
            return cloneElement(child, {
              onClick: () =>
                handleChildClick(child.props as Record<string, unknown>, index),
              active: index === activeId,
              ...itemProps[index],
            } as {
              onClick?: () => void;
              active?: boolean;
              [key: string]: unknown;
            });
          }

          return child;
        })}
      </ul>
    </Element>
  );
};

DropdownMenu.displayName = "DropdownMenu";
export { DropdownMenu };
