import { ReactNode } from 'react';
import { DateFieldSingleProps } from '../../../../components/DateFieldSingle';
import { DateFieldRangeProps } from '../../../../components/DateFieldRange';
import { SelectMenuOption, SelectMenuProps, SelectMenuSyncProps } from '../../../../components/SelectMenu';
import { MultiSelectMenuOption, MultiSelectMenuProps, MultiSelectMenuSyncProps } from '../../../../components/MultiSelectMenu';
import { TreeSelectMenuProps, TreeSelectMenuSyncProps, TreeSelectMenuValue } from '../../TreeSelectMenu';
import { DistributiveOmit } from '../../../../types';
/**
 * Base properties shared by all filter types
 */
export type BaseFilter = {
    /** Unique identifier for the filter */
    id: string;
    /** Display label for the filter */
    label: string;
    /** When true, the filter is only reachable via the drawer and never rendered inline in the toolbar */
    drawerOnly?: boolean;
};
/**
 * Built-in boolean filter type
 * Used for simple true/false filtering
 */
export type BooleanFilter = BaseFilter & {
    /** Identifies this as a boolean filter */
    type: "boolean";
    /** Current state of the boolean filter */
    checked: boolean;
};
/**
 * Props passed to custom filter render functions
 */
export type FilterRenderProps<T = unknown> = {
    /** Current value of the filter */
    value?: T;
    /** Callback to update the filter value */
    onChange: (value?: T) => void;
};
type CustomFilterShared<T> = BaseFilter & {
    /** Identifies this as a custom filter */
    type: "custom";
    /** Function to render the filter content in the drawer */
    drawerRender: (props: FilterRenderProps<T>) => ReactNode;
    /** Current value of the custom filter */
    value?: T;
    /** Optional number to display in a label chip */
    labelChipCount?: number;
};
/**
 * Custom filter type allowing for complex filter implementations.
 *
 * `buttonRender` is required for filters that can appear inline in the
 * toolbar, and forbidden when `drawerOnly: true` since the filter never
 * renders inline.
 */
export type CustomFilter<T = unknown> = (CustomFilterShared<T> & {
    drawerOnly: true;
    buttonRender?: never;
}) | (CustomFilterShared<T> & {
    drawerOnly?: false;
    /** Function to render the filter content in the button/popover */
    buttonRender: (props: FilterRenderProps<T>) => ReactNode;
});
/**
 * Single select filter type backed by SelectMenuSync (toolbar) and
 * SelectFieldSync (drawer). The consumer supplies a fixed `options` array;
 * client-side filtering happens automatically via match-sorter (override with
 * a custom `filter` function or MatchSorterOptions config).
 *
 * Uses DistributiveOmit so variant-specific fields survive — see AsyncSelectFilter.
 *
 * Filter-runtime concerns (`label`, `id`, `selectedOption`, `trigger`,
 * `value`/`onSelectedOptionChange`, focus-lifecycle callbacks) are owned by
 * FilterBar and the singleSelect adapter — consumers don't pass them.
 */
export type SingleSelectFilter = BaseFilter & {
    /** Identifies this as a single select filter */
    type: "singleSelect";
    /** Currently selected option */
    selectedOption?: SelectMenuOption;
    /**
     * When true, the drawer cell renders a Radio.Group over the full option set
     * instead of the default SelectFieldSync combobox. The toolbar still uses
     * SelectMenuSync regardless.
     */
    simpleDrawerVariant?: boolean;
} & DistributiveOmit<SelectMenuSyncProps, "id" | "label" | "value" | "onSelectedOptionChange" | "trigger" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose" | "clear">;
/**
 * Multi select filter type backed by MultiSelectMenuSync (toolbar) and
 * MultiSelectFieldSync (drawer). Same option/filter model as SingleSelectFilter.
 * Inherits MultiSelectMenuSync's simplified `selectAll` / `selectFiltered`
 * (boolean | { label }) — click handling and check state are managed automatically.
 */
export type MultiSelectFilter = BaseFilter & {
    /** Identifies this as a multi select filter */
    type: "multiSelect";
    /** Currently selected options */
    selectedOptions?: MultiSelectMenuOption[];
    /**
     * When true, the drawer cell renders a Checkbox.Group over the full option
     * set instead of the default MultiSelectFieldSync combobox. The toolbar
     * still uses MultiSelectMenuSync regardless.
     */
    simpleDrawerVariant?: boolean;
} & DistributiveOmit<MultiSelectMenuSyncProps, "id" | "label" | "value" | "onSelectedOptionsChange" | "trigger" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose" | "clear">;
/**
 * Which date constraint a typed value violated. Passed to a date filter's
 * `getErrorMessage` so consumers can supply the error copy.
 */
export type DateFilterErrorReason = "minDate" | "maxDate" | "unavailable";
/** Context passed to a `date` filter's `getErrorMessage` resolver. */
export type DateFilterErrorContext = {
    /** The constraint the typed value violated. */
    reason: DateFilterErrorReason;
    /** The offending value (ISO 8601). */
    value: string;
};
/** Context passed to a `dateRange` filter's `getErrorMessage` resolver. */
export type DateRangeFilterErrorContext = {
    /** The constraint the typed endpoint violated. */
    reason: DateFilterErrorReason;
    /** Which endpoint of the range violated the constraint. */
    field: "start" | "end";
    /** The offending value (ISO 8601). */
    value: string;
} | {
    /** The start date was after the end date. */
    reason: "startAfterEnd";
};
/**
 * Single date filter type using DateFieldSingle component
 * Used for selecting a single date with calendar support.
 *
 * `minDate` / `maxDate` (ISO 8601) and `unavailable` restrict which dates are
 * selectable in both the toolbar popover calendar and the drawer field. Typing
 * a value outside those constraints is still allowed, but surfaces an error
 * message on the field. Provide `getErrorMessage` to override the default copy.
 */
export type DateFilter = BaseFilter & Pick<DateFieldSingleProps, "value" | "mode" | "minDate" | "maxDate" | "unavailable"> & {
    type: "date";
    /**
     * Override the error message shown when a typed value violates a
     * constraint. Return the copy to display for the given reason. When
     * omitted, a default message is shown.
     */
    getErrorMessage?: (context: DateFilterErrorContext) => string;
};
/**
 * Date range filter type using DateFieldRange component
 * Used for selecting a date range with calendar support.
 *
 * `minDate` / `maxDate` (ISO 8601) and `unavailable` restrict which dates are
 * selectable in both the toolbar popover calendar and the drawer field. Typing
 * a value outside those constraints is still allowed, but surfaces an error
 * message on the field. Provide `getErrorMessage` to override the default copy.
 */
export type DateRangeFilter = BaseFilter & Pick<DateFieldRangeProps, "value" | "mode" | "minDate" | "maxDate" | "unavailable"> & {
    type: "dateRange";
    /**
     * Override the error message shown when a typed value violates a
     * constraint. Return the copy to display for the given reason. When
     * omitted, a default message is shown.
     */
    getErrorMessage?: (context: DateRangeFilterErrorContext) => string;
};
/**
 * Pre-defined library options the dateList filter always renders below the
 * consumer's options. Each opens a Dialog with a date picker. Callers must
 * not use these ids in their own `options`.
 */
export type DateListLibraryOptionId = "on" | "before" | "after" | "customRange";
/**
 * An option in a dateList filter. Consumer-supplied options commit their
 * `value` immediately on click. Library options share this shape with one
 * of the reserved `DateListLibraryOptionId` ids.
 */
export type DateListOption = {
    /** Unique identifier for the option */
    id: string;
    /** Display label for the option */
    label: string;
    /**
     * Concrete value the option resolves to: an ISO date string, a date range,
     * or `null` to represent "no filter applied" (treated as inactive).
     */
    value: string | {
        startDate: string;
        endDate: string;
    } | null;
};
/**
 * Date list filter type. Renders the consumer's options followed by built-in
 * default options (On…, Before…, After…, Custom Range…) that open a Dialog
 * with the appropriate date picker. Use `excludeDefaultOptions` to omit any
 * of those defaults.
 */
export type DateListFilter = BaseFilter & Pick<DateFieldSingleProps, "mode"> & {
    /** Identifies this as a date list filter */
    type: "dateList";
    /** Consumer-supplied options. Library options are auto-rendered below. */
    options: DateListOption[];
    /** The currently selected option (consumer or library) */
    selectedOption?: DateListOption;
    /**
     * Default option ids to omit from the menu (`on`, `before`, `after`,
     * `customRange`). Defaults to showing all four built-in options.
     */
    excludeDefaultOptions?: DateListLibraryOptionId[];
};
/**
 * Async select filter type. Backed by SelectMenu in the toolbar and SelectField
 * in the drawer, so the consumer supplies a `loadOptions` function instead of a
 * static `items` array. Carries the full SelectMenu loader union (eager + lazy
 * page/offset/group) plus pass-through configuration (pinned, cache, virtualize,
 * search, displayMenuAs, etc.).
 *
 * Uses DistributiveOmit so variant-specific fields like `lazyOptions` and
 * `groupToString` survive the omit — plain `Omit<SelectMenuProps, …>` would
 * silently drop them, since it reduces unions to their common keys.
 *
 * Filter-runtime concerns (`label`, `id`, `selectedOption`, `trigger`,
 * `value`/`onSelectedOptionChange`, focus-lifecycle callbacks) are owned by
 * FilterBar and the asyncSelect adapter — consumers don't pass them.
 */
export type AsyncSelectFilter = BaseFilter & {
    /** Identifies this as an async select filter */
    type: "asyncSelect";
    /** The currently selected option */
    selectedOption?: SelectMenuOption;
} & DistributiveOmit<SelectMenuProps, "id" | "label" | "value" | "onSelectedOptionChange" | "trigger" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose" | "clear">;
/**
 * Async multi-select filter type. The multi-selection counterpart of
 * AsyncSelectFilter — backed by MultiSelectMenu in the toolbar and
 * MultiSelectField in the drawer, so the consumer supplies a `loadOptions`
 * function instead of a static `items` array. Carries the full
 * MultiSelectMenu loader union and pass-through configuration, including the
 * `selectAll` and `selectFiltered` checkbox affordances.
 *
 * Filter-runtime concerns (`label`, `id`, `selectedOptions`, `trigger`,
 * `value`/`onSelectedOptionsChange`, focus-lifecycle callbacks) are owned by
 * FilterBar and the asyncMultiSelect adapter — consumers don't pass them.
 */
export type AsyncMultiSelectFilter = BaseFilter & {
    /** Identifies this as an async multi-select filter */
    type: "asyncMultiSelect";
    /** The currently selected options */
    selectedOptions?: MultiSelectMenuOption[];
} & DistributiveOmit<MultiSelectMenuProps, "id" | "label" | "value" | "onSelectedOptionsChange" | "trigger" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose" | "clear">;
/**
 * Value shape for a numeric range filter. Both bounds are optional —
 * consumers may set only `min`, only `max`, or both. `null` represents
 * "no filter applied" (treated as inactive).
 */
export type NumericRangeValue = {
    min?: number;
    max?: number;
} | null;
/**
 * Numeric min/max range filter. Renders two NumberField inputs (compact
 * stacked layout in the toolbar popover, side-by-side grid in the drawer).
 *
 * - `mode` toggles currency ($ prefix, 2dp) or percentage (% suffix, up to 3dp)
 *   decorators on both inputs and on the formatted label.
 * - `minValue` / `maxValue` clamp entered bounds to a valid range.
 * - `inclusiveBounds` switches the field labels between Min/Max (inclusive)
 *   and Above/Below (exclusive), and the label symbols between `≥`/`≤` and
 *   `>`/`<`.
 */
export type NumericRangeFilter = BaseFilter & {
    /** Identifies this as a numeric range filter */
    type: "numericRange";
    /** Current min/max value (or null when inactive) */
    value?: NumericRangeValue;
    /** Optional decorator mode applied to both inputs and the formatted label */
    mode?: "currency" | "percentage";
    /** Clamps entered values from below */
    minValue?: number;
    /** Clamps entered values from above */
    maxValue?: number;
    /** When true, label uses ≥/≤ and Min/Max; otherwise >/< and Above/Below */
    inclusiveBounds?: boolean;
    /** Increment for arrow-key / scroll adjustments on the NumberFields. */
    step?: number;
    /**
     * Override the minimum fraction digits applied to both inputs and the
     * formatted label. Defaults derived from `mode`: `2` for currency, `0`
     * for percentage, unset for plain.
     */
    minimumFractionDigits?: number;
    /**
     * Override the maximum fraction digits applied to both inputs and the
     * formatted label. Defaults derived from `mode`: `2` for currency, `3`
     * for percentage, unset for plain.
     */
    maximumFractionDigits?: number;
    /**
     * Hide the increment/decrement controls on the NumberFields.
     * @default true
     */
    hideControls?: boolean;
};
type TextInputFilterShared = BaseFilter & {
    /** Identifies this as a text input filter */
    type: "textInput";
    /** Current text value (undefined or empty means inactive) */
    value?: string;
    /** Placeholder shown when the field is empty */
    placeholder?: string;
};
/**
 * Single text input filter. Renders a TextField — the field's own label is
 * hidden inline in the toolbar (the filter button doubles as the label) and
 * shown in the drawer cell.
 *
 * `placeholder` is shown when the field is empty; `maxLength` clamps entered
 * text to that many characters. Set `showCounter: true` to render a
 * `current/max` character counter under the input — `maxLength` is required
 * (and must be a concrete `number`, not `undefined`) in that case, otherwise
 * the counter renders with an empty denominator.
 */
export type TextInputFilter = (TextInputFilterShared & {
    /** Show a `current/max` character counter under the input. */
    showCounter: true;
    /** Max character length; required when `showCounter` is true. */
    maxLength: number;
}) | (TextInputFilterShared & {
    /** Show a `current/max` character counter under the input. */
    showCounter?: false;
    /** Optional max character length; entered text is truncated to this length. */
    maxLength?: number;
});
/**
 * Pinned, always-visible search filter. Unlike other filter types, it never
 * renders as a trigger button/popover — it's a persistent search field
 * that's excluded from the toolbar's roving-tabindex pool so it stays
 * natively tabbable at all times (see FilterSearchField).
 *
 * FilterBar always renders it first among the inline filters, regardless of
 * where it sits in the `filters` array — keyboard navigation treats it as a
 * fixed edge of the filter sequence (`ArrowLeft` on the first filter chip
 * and `ArrowRight` on the last both jump to the search field), which only
 * makes spatial sense at that position.
 */
export type SearchFilter = BaseFilter & {
    /** Identifies this as a search filter */
    type: "search";
    /** Current text value (undefined or empty means inactive) */
    value?: string;
    /** Placeholder shown when the field is empty */
    placeholder?: string;
};
/**
 * Sync tree filter type. Backed by TreeSelectMenuSync in the toolbar and
 * TreeSelectFieldSync in the drawer, so the consumer supplies a static
 * `options` tree (with optional client-side `filter` override) instead of a
 * `loadOptions` function. Selection is always an array of node values, even in
 * `selectionMode: "single"`.
 *
 * Uses DistributiveOmit so variant-specific fields survive the omit, matching
 * the select-family filters.
 *
 * Filter-runtime concerns (`label`, `id`, `selectedNodes`, `trigger`,
 * `value`/`onSelectedOptionsChange`, focus-lifecycle callbacks) are owned by
 * FilterBar and the tree adapter — consumers don't pass them. Like the
 * select-family filters, the inline menu honors `controlledFiltering`: when it
 * is on, selections are buffered as a draft and commit only on Apply; when off,
 * they commit immediately.
 */
export type TreeFilter = BaseFilter & {
    /** Identifies this as a tree filter */
    type: "tree";
    /** Currently selected tree node values */
    selectedNodes?: TreeSelectMenuValue[];
} & DistributiveOmit<TreeSelectMenuSyncProps, "id" | "label" | "value" | "onSelectedOptionsChange" | "trigger" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose">;
/**
 * Async tree filter type. The async counterpart of TreeFilter — backed by
 * TreeSelectMenu in the toolbar and TreeSelectField in the drawer, so the
 * consumer supplies a `loadOptions` function (with `parentNode` for lazy branch
 * loading) instead of a static `options` tree. Carries the full TreeSelectMenu
 * pass-through configuration (cache, virtualize, displayMenuAs, initialLoad,
 * selectionMode, valueConsistsOf, etc.).
 *
 * Filter-runtime concerns (`label`, `id`, `selectedNodes`, `trigger`,
 * `value`/`onSelectedOptionsChange`, focus-lifecycle callbacks) are owned by
 * FilterBar and the asyncTree adapter — consumers don't pass them. Like
 * TreeFilter, the inline menu honors `controlledFiltering`: when it is on,
 * selections are buffered as a draft and commit only on Apply; when off, they
 * commit immediately.
 */
export type AsyncTreeFilter = BaseFilter & {
    /** Identifies this as an async tree filter */
    type: "asyncTree";
    /** Currently selected tree node values */
    selectedNodes?: TreeSelectMenuValue[];
} & DistributiveOmit<TreeSelectMenuProps, "id" | "label" | "value" | "onSelectedOptionsChange" | "trigger" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose">;
/**
 * Union type of all available filter types
 * Uses unknown instead of any for better type safety
 */
export type Filter = BooleanFilter | CustomFilter<any> | SingleSelectFilter | MultiSelectFilter | DateFilter | DateRangeFilter | DateListFilter | AsyncSelectFilter | AsyncMultiSelectFilter | TreeFilter | AsyncTreeFilter | NumericRangeFilter | TextInputFilter | SearchFilter;
/** Type representing all possible filter values */
export type FilterValue = boolean | CustomFilter["value"] | SingleSelectFilter["selectedOption"] | MultiSelectFilter["selectedOptions"] | DateFilter["value"] | DateRangeFilter["value"] | DateListFilter["selectedOption"] | AsyncSelectFilter["selectedOption"] | AsyncMultiSelectFilter["selectedOptions"] | TreeFilter["selectedNodes"] | AsyncTreeFilter["selectedNodes"] | NumericRangeFilter["value"] | TextInputFilter["value"] | SearchFilter["value"];
export {};
