import {
  useWrapElement,
  createElement,
  createHook,
  forwardRef,
} from "@ariakit/react-utils";
import type { Options, Props } from "@ariakit/react-utils";
import type { ElementType } from "react";
import { FocusableContext } from "./focusable-context.tsx";

const TagName = "div" satisfies ElementType;
type TagName = typeof TagName;

/**
 * Returns props to create a `FocusableContainer` component.
 * @see https://ariakit.com/components/focusable
 * @example
 * ```jsx
 * const props = useFocusableContainer();
 * <Role {...props} />
 * ```
 */
export const useFocusableContainer = createHook<
  TagName,
  FocusableContainerOptions
>(function useFocusableContainer({ autoFocusOnShow = true, ...props }) {
  props = useWrapElement(
    props,
    (element) => (
      <FocusableContext.Provider value={autoFocusOnShow}>
        {element}
      </FocusableContext.Provider>
    ),
    [autoFocusOnShow],
  );

  return props;
});

/**
 * Renders a div that wraps
 * [`Focusable`](https://ariakit.com/reference/focusable) components and
 * controls whether they can be auto-focused.
 * @see https://ariakit.com/components/focusable
 * @example
 * ```jsx
 * <FocusableContainer autoFocusOnShow={false}>
 *   <Focusable autoFocus />
 * </FocusableContainer>
 * ```
 */
export const FocusableContainer = forwardRef(function FocusableContainer(
  props: FocusableContainerProps,
) {
  const htmlProps = useFocusableContainer(props);
  return createElement(TagName, htmlProps);
});

export interface FocusableContainerOptions<
  _T extends ElementType = TagName,
> extends Options {
  /**
   * Determines whether [`Focusable`](https://ariakit.com/reference/focusable)
   * elements inside the container should be automatically focused when the
   * container is shown and they have the
   * [`autoFocus`](https://ariakit.com/reference/focusable#autofocus) prop.
   * @default true
   */
  autoFocusOnShow?: boolean;
}

export type FocusableContainerProps<T extends ElementType = TagName> = Props<
  T,
  FocusableContainerOptions<T>
>;
