import { useStoreState } from "@ariakit/react-store";
import type { PickRequired, ToPrimitive } from "@ariakit/utils";
import type { ReactNode } from "react";
import { useSelectContext } from "./select-context.tsx";
import type { SelectStore, SelectStoreValue } from "./select-store.ts";

type Value = SelectStoreValue;

/**
 * Renders the current
 * [`value`](https://ariakit.com/reference/use-select-store#value) state in the
 * [select store](https://ariakit.com/reference/use-select-store).
 *
 * As a value component, it doesn't render any DOM elements and therefore
 * doesn't accept HTML props. It can optionally accept a
 * [`fallback`](https://ariakit.com/reference/select-value#fallback) prop to use
 * as a default value if the store's value is an empty string or empty array.
 *
 * The store's
 * [`value`](https://ariakit.com/reference/use-select-store#value) is
 * otherwise rendered as-is.
 *
 * Additionally, it takes a
 * [`children`](https://ariakit.com/reference/select-value#children) function
 * that gets called with the current value as an argument. This is handy for
 * rendering the value in a custom way.
 * @deprecated Use
 * [`ComboboxSelectedValue`](https://ariakit.com/reference/combobox-selected-value)
 * instead.
 * @see https://ariakit.com/components/select
 * @example
 * ```jsx {3}
 * <SelectProvider>
 *   <Select>
 *     <SelectValue fallback="Select a value" />
 *     <SelectArrow />
 *   </Select>
 *   <SelectPopover>
 *     <SelectItem value="Apple" />
 *     <SelectItem value="Banana" />
 *     <SelectItem value="Orange" />
 *   </SelectPopover>
 * </SelectProvider>
 * ```
 * @example
 * ```jsx {1-3,7}
 * function renderValue(value) {
 *   // render custom JSX
 * }
 *
 * <SelectProvider>
 *   <Select>
 *     <SelectValue>{renderValue}</SelectValue>
 *     <SelectArrow />
 *   </Select>
 *   <SelectPopover>
 *     <SelectItem value="Apple" />
 *     <SelectItem value="Banana" />
 *     <SelectItem value="Orange" />
 *   </SelectPopover>
 * </SelectProvider>
 * ```
 */

export function SelectValue<T extends Value = Value>(
  props: PickRequired<SelectValueProps<T>, "fallback">,
): T;

/** @deprecated Use `ComboboxSelectedValue` instead. */
export function SelectValue(props?: SelectValueProps): Value;

export function SelectValue({
  store,
  fallback,
  children,
}: SelectValueProps = {}) {
  const context = useSelectContext();
  store = store || context;

  const value = useStoreState(store, ["value"], (state) => {
    if (!state?.value.length) return fallback;
    return state.value;
  });

  if (children) {
    return children(value || "");
  }

  return value;
}

/** @deprecated Use `ComboboxSelectedValueProps` instead. */
export interface SelectValueProps<T extends Value = Value> {
  /**
   * Object returned by the
   * [`useSelectStore`](https://ariakit.com/reference/use-select-store) hook. If
   * not provided, the parent
   * [`SelectList`](https://ariakit.com/reference/select-list) or
   * [`SelectPopover`](https://ariakit.com/reference/select-popover) components'
   * context will be used.
   */
  store?: SelectStore<T>;
  /**
   * The value to use as a default if the store's value is an empty string or
   * empty array.
   *
   * The store's
   * [`value`](https://ariakit.com/reference/use-select-store#value) is
   * otherwise rendered as-is.
   * @default ""
   */
  fallback?: T;
  /**
   * A function that gets called with the current value as an argument. This is
   * handy for rendering the value in a custom way.
   */
  children?: (value: ToPrimitive<T>) => ReactNode;
}
