import type { ReactNode } from 'react';
import { useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
import type { ButtonSize, ButtonVariant } from '../button/Button';
import { Button } from '../button/Button';
import './dropdown-button.css';

export type DropdownButtonItem =
  | {
      type?: 'item';
      label: ReactNode;
      onClick?: () => void;
      href?: string;
      disabled?: boolean;
      endAdornment?: ReactNode;
    }
  | { type: 'divider' };

export type DropdownButtonAlign = 'start' | 'end';

export type DropdownButtonProps = {
  label: ReactNode;
  items: DropdownButtonItem[];
  variant?: ButtonVariant;
  size?: ButtonSize;
  outline?: boolean;
  disabled?: boolean;
  align?: DropdownButtonAlign;
  menuWidth?: number | string;
  closeOnItemClick?: boolean;
  ariaLabel?: string;
  className?: string;
};

export function DropdownButton({
  label,
  items,
  variant = 'secondary',
  size,
  outline = false,
  disabled = false,
  align = 'start',
  menuWidth,
  closeOnItemClick = true,
  ariaLabel,
  className,
}: DropdownButtonProps) {
  const uid = useId().replace(/:/g, '');
  const rootRef = useRef<HTMLDivElement>(null);
  const [open, setOpen] = useState(false);
  const [isToggling, setIsToggling] = useState(false);

  const menuId = `ccl-dropdown-button-menu-${uid}`;

  const toggle = useCallback(() => {
    if (disabled) return;
    setIsToggling(true);
    setOpen((v) => !v);
    window.setTimeout(() => setIsToggling(false), 0);
  }, [disabled]);

  const close = useCallback(() => setOpen(false), []);

  useLayoutEffect(() => {
    const onDocClick = (event: MouseEvent) => {
      if (!open || isToggling) return;
      const target = event.target as Node;
      if (rootRef.current?.contains(target)) return;
      close();
    };

    const onDocKey = (event: KeyboardEvent) => {
      if (!open) return;
      if (event.key === 'Escape') {
        event.preventDefault();
        close();
      }
    };

    document.addEventListener('click', onDocClick, true);
    document.addEventListener('keydown', onDocKey, true);
    return () => {
      document.removeEventListener('click', onDocClick, true);
      document.removeEventListener('keydown', onDocKey, true);
    };
  }, [close, isToggling, open]);

  const menuStyle = useMemo(() => {
    if (menuWidth == null) return undefined;
    return { width: typeof menuWidth === 'number' ? `${menuWidth}px` : menuWidth } as const;
  }, [menuWidth]);

  return (
    <div
      ref={rootRef}
      className={['ccl-dropdown-button', open ? 'ccl-dropdown-button--open' : '', className ?? ''].filter(Boolean).join(' ')}
    >
      <Button
        variant={variant}
        size={size}
        outline={outline}
        disabled={disabled}
        ariaLabel={typeof ariaLabel === 'string' ? ariaLabel : undefined}
        ariaExpanded={open}
        aria-haspopup="menu"
        aria-controls={menuId}
        onClick={toggle}
        className="ccl-dropdown-button__toggle"
      >
        <span className="ccl-dropdown-button__label">{label}</span>
        <span className="ccl-dropdown-button__caret" aria-hidden>
          ▼
        </span>
      </Button>

      {open ? (
        <div
          id={menuId}
          className={['ccl-dropdown-button__menu', align === 'end' ? 'ccl-dropdown-button__menu--end' : '']
            .filter(Boolean)
            .join(' ')}
          style={menuStyle}
          role="menu"
          aria-label={typeof ariaLabel === 'string' ? ariaLabel : 'Dropdown menu'}
          onClick={(e) => e.stopPropagation()}
        >
          {items.map((item, idx) => {
            if (item.type === 'divider') {
              return <div key={`div-${idx}`} className="ccl-dropdown-button__divider" role="separator" />;
            }

            const isDisabled = !!item.disabled;
            const common = {
              key: `item-${idx}`,
              className: ['ccl-dropdown-button__item', isDisabled ? 'ccl-dropdown-button__item--disabled' : '']
                .filter(Boolean)
                .join(' '),
              role: 'menuitem' as const,
              'aria-disabled': isDisabled || undefined,
              tabIndex: isDisabled ? -1 : 0,
              onClick: () => {
                if (isDisabled) return;
                item.onClick?.();
                if (closeOnItemClick) close();
              },
            };

            const content = (
              <>
                <span className="ccl-dropdown-button__item-label">{item.label}</span>
                {item.endAdornment ? <span className="ccl-dropdown-button__item-end">{item.endAdornment}</span> : null}
              </>
            );

            if (item.href) {
              return (
                <a {...common} href={isDisabled ? undefined : item.href} onClick={(e) => (isDisabled ? e.preventDefault() : common.onClick())}>
                  {content}
                </a>
              );
            }

            return (
              <button
                {...common}
                type="button"
                disabled={isDisabled}
                onKeyDown={(e) => {
                  if (e.key === 'Enter' || e.key === ' ') {
                    e.preventDefault();
                    (e.currentTarget as HTMLButtonElement).click();
                  }
                }}
              >
                {content}
              </button>
            );
          })}
        </div>
      ) : null}
    </div>
  );
}

