'use client';

import * as React from 'react';
import { useForkRef } from '../utils/useForkRef.js';
import { makeEventPreventable, mergeProps } from '../merge-props/index.js';
import { useEnhancedEffect } from '../utils/useEnhancedEffect.js';
import { useEventCallback } from '../utils/useEventCallback.js';
import { useRootElementName } from '../utils/useRootElementName.js';
import { useCompositeRootContext } from '../composite/root/CompositeRootContext.js';
export function useButton(parameters = {}) {
  const {
    buttonRef: externalRef,
    disabled = false,
    focusableWhenDisabled,
    tabIndex,
    type,
    elementName: elementNameProp
  } = parameters;
  const buttonRef = React.useRef(null);
  const {
    rootElementName: elementName,
    updateRootElementName
  } = useRootElementName({
    rootElementName: elementNameProp
  });
  const isCompositeItem = useCompositeRootContext(true) !== undefined;
  const isNativeButton = useEventCallback(() => {
    const element = buttonRef.current;
    return elementName === 'BUTTON' || elementName === 'INPUT' && ['button', 'submit', 'reset'].includes(element?.type);
  });
  const isValidLink = useEventCallback(() => {
    const element = buttonRef.current;
    return Boolean(elementName === 'A' && element?.href);
  });
  const mergedRef = useForkRef(updateRootElementName, externalRef, buttonRef);
  const buttonProps = React.useMemo(() => {
    const additionalProps = {};
    if (tabIndex !== undefined && !isCompositeItem) {
      additionalProps.tabIndex = tabIndex;
    }
    if (elementName === 'BUTTON' || elementName === 'INPUT') {
      if (focusableWhenDisabled || isCompositeItem) {
        additionalProps['aria-disabled'] = disabled;
      } else if (!isCompositeItem) {
        additionalProps.disabled = disabled;
      }
    } else if (elementName !== '') {
      if (elementName !== 'A') {
        additionalProps.role = 'button';
        if (!isCompositeItem) {
          additionalProps.tabIndex = tabIndex ?? 0;
        }
      } else if (tabIndex && !isCompositeItem) {
        additionalProps.tabIndex = tabIndex;
      }
      if (disabled) {
        additionalProps['aria-disabled'] = disabled;
        if (!isCompositeItem) {
          additionalProps.tabIndex = focusableWhenDisabled ? tabIndex ?? 0 : -1;
        }
      }
    }
    return additionalProps;
  }, [disabled, elementName, focusableWhenDisabled, isCompositeItem, tabIndex]);

  // handles a disabled composite button rendering another button, e.g.
  // <Toolbar.Button disabled render={<Menu.Trigger />} />
  // the `disabled` prop needs to pass through 2 `useButton`s then finally
  // delete the `disabled` attribute from DOM
  useEnhancedEffect(() => {
    const element = buttonRef.current;
    if (!(element instanceof HTMLButtonElement)) {
      return;
    }
    if (isCompositeItem && disabled && buttonProps.disabled === undefined && element.disabled) {
      element.disabled = false;
    }
  }, [disabled, buttonProps.disabled, isCompositeItem]);
  const getButtonProps = React.useCallback((externalProps = {}) => {
    const {
      onClick: externalOnClick,
      onMouseDown: externalOnMouseDown,
      onKeyUp: externalOnKeyUp,
      onKeyDown: externalOnKeyDown,
      onPointerDown: externalOnPointerDown,
      ...otherExternalProps
    } = externalProps;
    return mergeProps({
      type,
      onClick(event) {
        if (disabled) {
          event.preventDefault();
          return;
        }
        externalOnClick?.(event);
      },
      onMouseDown(event) {
        if (!disabled) {
          externalOnMouseDown?.(event);
        }
      },
      onKeyDown(event) {
        if (
        // allow Tabbing away from focusableWhenDisabled buttons
        disabled && focusableWhenDisabled && event.key !== 'Tab' || event.target === event.currentTarget && !isNativeButton() && event.key === ' ') {
          event.preventDefault();
        }
        if (!disabled) {
          makeEventPreventable(event);
          externalOnKeyDown?.(event);
        }
        if (event.baseUIHandlerPrevented) {
          return;
        }

        // Keyboard accessibility for non interactive elements
        if (event.target === event.currentTarget && !isNativeButton() && !isValidLink() && event.key === 'Enter' && !disabled) {
          externalOnClick?.(event);
          event.preventDefault();
        }
      },
      onKeyUp(event) {
        // calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
        // https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
        // Keyboard accessibility for non interactive elements
        if (!disabled) {
          makeEventPreventable(event);
          externalOnKeyUp?.(event);
        }
        if (event.baseUIHandlerPrevented) {
          return;
        }
        if (event.target === event.currentTarget && !isNativeButton() && !disabled && event.key === ' ') {
          externalOnClick?.(event);
        }
      },
      onPointerDown(event) {
        if (disabled) {
          event.preventDefault();
          return;
        }
        externalOnPointerDown?.(event);
      },
      ref: mergedRef
    }, buttonProps, otherExternalProps);
  }, [buttonProps, disabled, focusableWhenDisabled, isNativeButton, isValidLink, mergedRef, type]);
  return {
    getButtonProps,
    buttonRef: mergedRef
  };
}