import { AriaAttributes, CSSProperties, ReactElement, ReactNode } from 'react';
import { AiMarkWithTooltipOrPopoverProps, LayoutUtilProps, Size } from '../../types';
import { SelectFieldGroupByValue, SelectFieldOption, SelectFieldOptionContent } from '../SelectField/types';
import { ChipProps } from '../../components/Chip';
import { AddNewItemProps } from '../../internal/types/addNewItemTypes';
import { BulkActionConfig } from '../../internal/types/bulkActionTypes';
/**
 * Partial chip props that can be returned from the `getChipProps` callback.
 * Supports `icon` or `avatar` (mutually exclusive) and all other chip props as optional overrides.
 * Core props (`label`, `onClose`, `className`, `title`, `size`) are managed by the component and excluded from this type.
 */
export type MultiSelectFieldChipProps = Partial<Omit<ChipProps, "icon" | "avatar" | "label" | "onClose" | "className" | "title" | "size">> & ({
    icon?: ChipProps["icon"];
    avatar?: never;
} | {
    icon?: never;
    avatar?: ChipProps["avatar"];
});
/**
 * Configuration options for the MultiSelectField cache.
 * @property enabled - Whether caching is enabled. Defaults to true.
 * @property maxSize - Maximum number of cached entries before clearing the cache. Defaults to 15.
 */
export type MultiSelectFieldCacheOptions = {
    enabled?: boolean;
    maxSize?: number;
};
/**
 * Imperative handle for the MultiSelectField component.
 * @property clearCache - Clears the options cache.
 * @property invalidate - Clears the cache and triggers a fresh options load from the data source.
 */
export type MultiSelectFieldHandle = {
    clearCache: () => void;
    invalidate: () => void;
};
export type MultiSelectFieldGroupByValue = SelectFieldGroupByValue;
/**
 * Rich content configuration for a MultiSelectField option row.
 * Controls the avatar, icon, description, and chip display within an option.
 */
export type MultiSelectFieldOptionContent = SelectFieldOptionContent;
export type MultiSelectFieldOption = SelectFieldOption;
export type MultiSelectFieldGroupedOption = MultiSelectFieldOption & {
    group: MultiSelectFieldGroupByValue;
};
export type MultiSelectFieldUngroupedOption = Omit<MultiSelectFieldOption, "group"> & {
    group?: never;
};
export type MultiSelectFieldOptionsResult = MultiSelectFieldOption[] | Promise<MultiSelectFieldOption[]>;
export type MultiSelectFieldEagerLoader = (searchValue: string) => MultiSelectFieldOptionsResult;
export type MultiSelectFieldOffsetLazyResult = {
    options: MultiSelectFieldUngroupedOption[];
    hasMore?: boolean;
};
export type MultiSelectFieldOffsetLazyLoader = (searchValue: string, offset: number, limit: number) => MultiSelectFieldOffsetLazyResult | Promise<MultiSelectFieldOffsetLazyResult>;
export type MultiSelectFieldPageLazyResult = {
    options: MultiSelectFieldUngroupedOption[];
    hasMore?: boolean;
};
export type MultiSelectFieldPageLazyLoader = (searchValue: string, pageNumber: number, pageSize: number) => MultiSelectFieldPageLazyResult | Promise<MultiSelectFieldPageLazyResult>;
export type MultiSelectFieldGroupLazyResult = {
    options: MultiSelectFieldGroupedOption[];
    hasMore?: boolean;
};
export type MultiSelectFieldGroupLazyLoader = (searchValue: string, previousGroupKey: MultiSelectFieldGroupByValue | null) => MultiSelectFieldGroupLazyResult | Promise<MultiSelectFieldGroupLazyResult>;
export type MultiSelectFieldSearchProps = {
    /**
     * The current search value.
     * Not a preferred usage. You likely don't need to control the searchValue yourself.
     */
    searchValue?: string;
    /**
     * Callback when the search value changes.
     * Not a preferred usage. Lean on the searchValue in the loadOptions function instead.
     */
    onSearchChange?: (searchValue: string) => void;
    /**
     * The number of milliseconds to debounce the search input.
     */
    debounceMs?: number;
};
export type MultiSelectFieldPinnedOptionsSection = {
    options: MultiSelectFieldOption[] | ((searchValue: string) => MultiSelectFieldOption[] | Promise<MultiSelectFieldOption[]>);
    label: string;
    /**
     * Whether to re-call the loader when search value changes.
     * Only applies when `options` is a function. Defaults to true.
     * When false, the loader is called once and the result is reused for all search values.
     *
     * You may wish to use this, for example, if you are loading a set of "favorites" options that should not be re-loaded when the search value changes.
     */
    searchReactive?: boolean;
    /**
     * Maximum number of search results to cache per section.
     * Only applies when `options` is a function and `searchReactive` is true.
     * Oldest entries are evicted when the limit is reached. Defaults to 15.
     */
    cacheSize?: number;
};
/**
 * There are two ways to configure pinned options.
 * 1. A labeled pinned options object (e.g. "Favorites", "Recent", "AI Suggestions", etc.)
 * 2. An array of labeled pinned options objects (e.g. [{"label": "Favorites", "options": [...]}])
 */
export type MultiSelectFieldPinnedOptions = MultiSelectFieldPinnedOptionsSection | MultiSelectFieldPinnedOptionsSection[];
type MultiSelectFieldCommonProps = {
    /**
     * The id of the multi-select field.
     */
    id?: string;
    /**
     * The label of the multi-select field.
     */
    label: string;
    /**
     * The placeholder of the multi-select field.
     */
    placeholder?: string;
    /**
     * The size of the multi-select field.
     */
    size?: Extract<Size, "small" | "medium" | "large">;
    /**
     * The selected options. Must be controlled state.
     */
    value: MultiSelectFieldOption[];
    /**
     * The callback to call when the selected options change.
     * @param options - The new array of selected options.
     */
    onSelectedOptionsChange: (options: MultiSelectFieldOption[]) => void;
    /**
     * Defines the initial loading behavior of the options. Controls when loadOptions is called.
     * @default "auto"
     * @description "auto" default behavior, currently equivalent to "immediate".
     * @description "immediate" will load the initial options when the component is mounted.
     * @description "open" will load the initial options if/when the user opens the dropdown.
     */
    initialLoad?: "auto" | "immediate" | "open";
    /**
     * The options to pin to the top of the list.
     */
    pinned?: MultiSelectFieldPinnedOptions;
    /**
     * Configuration for caching loadOptions results.
     * Caching is enabled by default. Set `{ enabled: false }` to disable.
     */
    cache?: MultiSelectFieldCacheOptions;
    /**
     * The way to display the menu.
     * @default "auto"
     * @description "auto" will display the menu as a popover on mobile and a dialog on desktop.
     * @description "popover" will always display the menu as a popover.
     * @description "dialog" will always display the menu as a dialog.
     */
    displayMenuAs?: "auto" | "popover" | "dialog";
    /**
     * Error state for the field. Pass `true` to indicate error styling without a message.
     * Pass a string, string[], or ReactElement (deprecated) for error messages.
     */
    error?: boolean | string | ReactElement | string[];
    /**
     * Visually hides the label while keeping it accessible to screen readers.
     * @default false
     */
    hideLabel?: boolean;
    /**
     * Hint text displayed below the input field.
     */
    hint?: ReactElement | string;
    /**
     * Additional information to display in a tooltip next to the label.
     */
    moreInfo?: ReactNode;
    /**
     * Description text displayed below the input field.
     */
    description?: ReactElement | string;
    /**
     * @deprecated No longer used. Error messages always use `aria-live="assertive"`.
     */
    errorAriaLive?: AriaAttributes["aria-live"];
    /**
     * Warning message(s) to display. Supports a single string or an array of strings.
     */
    warning?: string | string[];
    /**
     * Whether the field is required. Shows a red asterisk (*) next to the label.
     */
    required?: boolean;
    /**
     * AI mark configuration to display next to the label.
     * Can be a boolean to show a simple AI mark, or an object with tooltip/popover configuration.
     */
    labelAiMark?: AiMarkWithTooltipOrPopoverProps["aiMark"];
    /**
     * Whether the field is disabled.
     * When disabled, the input is still focusable but menu items cannot be selected.
     */
    disabled?: boolean;
    /**
     * Whether the field is read-only.
     * When read-only, the input is still focusable but menu items cannot be selected.
     */
    readOnly?: boolean;
    /**
     * When `true`, applies a subdued primary background to the field to draw attention to it.
     * @default false
     */
    isHighlighted?: boolean;
    /**
     * Content to display before the input field.
     */
    prefix?: string | ReactElement;
    /**
     * Content to display after the input field.
     */
    suffix?: string | ReactElement;
    /**
     * Configuration for the "Select All" option at the top of the list.
     * When provided, a "Select All" option will be shown while the search input is empty.
     *
     * Pass exactly one of `onClick` (fire-and-forget; the consumer commits via
     * `onSelectedOptionsChange`) or `compute` (returns the next selection; the
     * field commits the result for you, with sync or async support).
     *
     * While a `compute` promise is pending, the bulk row shows a loading state,
     * all option rows are disabled, and stale resolutions are silently discarded.
     *
     * `checkState` may be a static value or a function of the current selection,
     * so the row's checkbox can reflect how much of the set is selected.
     *
     * Select All and Select Filtered are mutually exclusive:
     * - Select All is shown when the search input is empty.
     * - Select Filtered (if provided) is shown when a search term is active.
     */
    selectAll?: BulkActionConfig;
    /**
     * Function that receives the current search value and returns configuration for
     * the "Select Filtered" option at the top of the list.
     *
     * When provided and a search term is active, a "Select Filtered" option will be shown
     * instead of "Select All". This allows selecting all options matching the current filter.
     *
     * See `selectAll` for the `onClick` / `compute` choice.
     *
     * Select All and Select Filtered are mutually exclusive:
     * - Select All (if provided) is shown when the search input is empty.
     * - Select Filtered is shown when a search term is active.
     *
     * @param searchValue - The current search input value
     * @returns BulkActionConfig describing the row
     */
    selectFiltered?: (searchValue: string) => BulkActionConfig;
    /**
     * When true, restricts the field to a single row height.
     * Overflow chips will be collapsed into a "+N" indicator.
     * @default false
     */
    singleRow?: boolean;
    /**
     * Maximum number of chips to display before showing a "+N" indicator.
     * Applies regardless of fixedHeight setting.
     * @default 10
     */
    maxChips?: number;
    /**
     * Custom CSS class name for the wrapper element.
     */
    className?: string;
    /**
     * Custom inline styles for the wrapper element.
     */
    style?: CSSProperties;
    /**
     * Whether to virtualize the dropdown list using windowed rendering.
     * Enable this for large option sets to improve performance by only rendering visible items.
     * @default false
     */
    virtualize?: boolean;
    /**
     * Whether to disable the search input.
     * When true, the input is replaced with a non-editable select trigger and the ARIA pattern
     * changes from combobox to listbox.
     * @default false
     */
    disableSearch?: boolean;
    /**
     * Callback to customize chip props for each selected option.
     * Allows customizing chip appearance (color, icon, avatar, etc.) per option.
     * Core props (label, onClose, className, title, size) are managed by the component and excluded from this type.
     * @param option - The selected option the chip represents
     * @returns Partial chip props to merge onto the chip
     */
    getChipProps?: (option: MultiSelectFieldOption) => MultiSelectFieldChipProps;
} & MultiSelectFieldSearchProps & LayoutUtilProps & AddNewItemProps;
type MultiSelectFieldGroupingProps = {
    /**
     * Function to convert a group value to a display label.
     * Only used when options have a `group` property.
     * @param groupValue - The group value from the option's `group` property
     * @returns The formatted group label
     */
    groupToString?: (groupValue: MultiSelectFieldGroupByValue) => string;
    /**
     * Custom comparator function to sort groups.
     * Receives two group values and returns a number indicating sort order.
     * Without this, groups appear in the order they are first encountered.
     * @param a - First group value to compare
     * @param b - Second group value to compare
     * @returns Negative if a < b, positive if a > b, zero if equal
     */
    groupSorter?: (a: MultiSelectFieldGroupByValue, b: MultiSelectFieldGroupByValue) => number;
};
type MultiSelectFieldNonGroupingProps = {
    /**
     * Incompatible with non-group lazy loading.
     */
    groupToString?: never;
    /**
     * Incompatible with non-group lazy loading.
     */
    groupSorter?: never;
};
export type MultiSelectFieldPropsLazyPage = MultiSelectFieldCommonProps & {
    /**
     * Lazy loading mode using page-based pagination.
     * Options will be loaded on demand when the user scrolls to the bottom of the list.
     * This mode only supports flat options (i.e. cannot be used with grouped options).
     */
    lazy: "page";
    lazyOptions?: {
        pageSize?: number;
    };
    /**
     * Function to load the options.
     */
    loadOptions: MultiSelectFieldPageLazyLoader;
} & MultiSelectFieldNonGroupingProps;
export type MultiSelectFieldPropsLazyOffset = MultiSelectFieldCommonProps & {
    /**
     * Lazy loading mode using offset-based pagination.
     * Options will be loaded on demand when the user scrolls to the bottom of the list.
     * This mode only supports flat options (i.e. cannot be used with grouped options).
     */
    lazy: "offset";
    lazyOptions?: {
        limit?: number;
    };
    /**
     * Function to load the options.
     */
    loadOptions: MultiSelectFieldOffsetLazyLoader;
} & MultiSelectFieldNonGroupingProps;
export type MultiSelectFieldPropsLazyGroup = MultiSelectFieldCommonProps & {
    /**
     * Lazy loading mode using incremental group loading.
     * Groups will be loaded on demand when the user scrolls to the bottom of the list.
     * This mode supports grouped options.
     */
    lazy: "group";
    lazyOptions?: object;
    /**
     * Function to load the options.
     */
    loadOptions: MultiSelectFieldGroupLazyLoader;
} & MultiSelectFieldGroupingProps;
export type MultiSelectFieldPropsEager = MultiSelectFieldCommonProps & {
    /**
     * Whether the options are lazy loaded. If true, the options will be loaded on demand when the user scrolls to the bottom of the list.
     * @default false
     */
    lazy?: false;
    /**
     * Function to load the options.
     */
    loadOptions: MultiSelectFieldEagerLoader;
} & MultiSelectFieldGroupingProps;
export type MultiSelectFieldPropsLazy = MultiSelectFieldPropsLazyPage | MultiSelectFieldPropsLazyOffset | MultiSelectFieldPropsLazyGroup;
export type MultiSelectFieldProps = MultiSelectFieldPropsLazy | MultiSelectFieldPropsEager;
export {};
