import { createElement, createHook, forwardRef } from "@ariakit/react-utils";
import type { Props } from "@ariakit/react-utils";
import type { ElementType } from "react";
import { useContext } from "react";
import type { CheckboxCheckOptions } from "../checkbox/checkbox-check.tsx";
import { useCheckboxCheck } from "../checkbox/checkbox-check.tsx";
import { MenuItemCheckedContext } from "./menu-context.tsx";
import type { MenuStore } from "./menu-store.ts";

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

/**
 * Returns props to create a `MenuItemCheck` component.
 * @see https://ariakit.com/components/menu
 * @example
 * ```jsx
 * const props = useMenuItemCheck({ checked: true });
 * <Role {...props} />
 * ```
 */
export const useMenuItemCheck = createHook<TagName, MenuItemCheckOptions>(
  function useMenuItemCheck({ store, checked, ...props }) {
    const context = useContext(MenuItemCheckedContext);
    checked = checked ?? context;
    props = useCheckboxCheck({ ...props, checked });
    return props;
  },
);

/**
 * Renders a checkmark icon when the
 * [`checked`](https://ariakit.com/reference/menu-item-check#checked) prop is
 * `true`. The icon can be overridden by providing a different one as children.
 *
 * When rendered inside
 * [`MenuItemCheckbox`](https://ariakit.com/reference/menu-item-checkbox) or
 * [`MenuItemRadio`](https://ariakit.com/reference/menu-item-radio) components,
 * the [`checked`](https://ariakit.com/reference/menu-item-check#checked) prop
 * is automatically derived from the context.
 * @see https://ariakit.com/components/menu
 * @example
 * ```jsx {5,9}
 * <MenuProvider defaultValues={{ apple: true, orange: false }}>
 *   <MenuButton>Fruits</MenuButton>
 *   <Menu>
 *     <MenuItemCheckbox name="apple">
 *       <MenuItemCheck />
 *       Apple
 *     </MenuItemCheckbox>
 *     <MenuItemCheckbox name="orange">
 *       <MenuItemCheck />
 *       Orange
 *     </MenuItemCheckbox>
 *   </Menu>
 * </MenuProvider>
 * ```
 */
export const MenuItemCheck = forwardRef(function MenuItemCheck(
  props: MenuItemCheckProps,
) {
  const htmlProps = useMenuItemCheck(props);
  return createElement(TagName, htmlProps);
});

export interface MenuItemCheckOptions<
  T extends ElementType = TagName,
> extends Omit<CheckboxCheckOptions<T>, "store"> {
  /**
   * Object returned by the
   * [`useMenuStore`](https://ariakit.com/reference/use-menu-store) hook. This
   * prop doesn't affect the checkmark. It's accepted for consistency with
   * other Ariakit components and is not passed to the underlying element. The
   * checked state is derived solely from the
   * [`checked`](https://ariakit.com/reference/menu-item-check#checked) prop or,
   * when it's not provided, from the closest
   * [`MenuItemCheckbox`](https://ariakit.com/reference/menu-item-checkbox) or
   * [`MenuItemRadio`](https://ariakit.com/reference/menu-item-radio)
   * component.
   */
  store?: MenuStore;
}

export type MenuItemCheckProps<T extends ElementType = TagName> = Props<
  T,
  MenuItemCheckOptions<T>
>;
