import { CollectionItem, ListCollection, GridCollection, SelectionMode, Selection } from '@zag-js/collection';
import { Machine, EventObject, Service } from '@zag-js/core';
import { TypeaheadState } from '@zag-js/dom-query';
import { PropTypes, RequiredBy, DirectionProperty, CommonProperties } from '@zag-js/types';

interface ValueChangeDetails<T extends CollectionItem = CollectionItem> {
    value: string[];
    items: T[];
}
interface HighlightChangeDetails<T extends CollectionItem = CollectionItem> {
    highlightedValue: string | null;
    highlightedItem: T | null;
    highlightedIndex: number;
}
interface ScrollToIndexDetails {
    index: number;
    immediate?: boolean | undefined;
    getElement: () => HTMLElement | null;
}
interface SelectionDetails {
    value: string;
}
type ElementIds = Partial<{
    root: string;
    content: string;
    label: string;
    item: (id: string | number) => string;
    itemGroup: (id: string | number) => string;
    itemGroupLabel: (id: string | number) => string;
}>;
interface ListboxProps<T extends CollectionItem = CollectionItem> extends DirectionProperty, CommonProperties {
    /**
     * The orientation of the listbox.
     * @default "vertical"
     */
    orientation?: "horizontal" | "vertical" | undefined;
    /**
     * The item collection
     */
    collection: ListCollection<T> | GridCollection<T>;
    /**
     * The ids of the elements in the listbox. Useful for composition.
     */
    ids?: ElementIds | undefined;
    /**
     * Whether the listbox is disabled
     */
    disabled?: boolean | undefined;
    /**
     * Whether to disallow selecting all items when `meta+a` is pressed
     */
    disallowSelectAll?: boolean | undefined;
    /**
     * The callback fired when the highlighted item changes.
     */
    onHighlightChange?: ((details: HighlightChangeDetails<T>) => void) | undefined;
    /**
     * The callback fired when the selected item changes.
     */
    onValueChange?: ((details: ValueChangeDetails<T>) => void) | undefined;
    /**
     * The controlled keys of the selected items
     */
    value?: string[] | undefined;
    /**
     * The initial default value of the listbox when rendered.
     * Use when you don't need to control the value of the listbox.
     *
     * @default []
     */
    defaultValue?: string[] | undefined;
    /**
     * The controlled key of the highlighted item
     */
    highlightedValue?: string | null | undefined;
    /**
     * The initial value of the highlighted item when opened.
     * Use when you don't need to control the highlighted value of the listbox.
     */
    defaultHighlightedValue?: string | null | undefined;
    /**
     * Whether to loop the keyboard navigation through the options
     * @default false
     */
    loopFocus?: boolean | undefined;
    /**
     * How multiple selection should behave in the listbox.
     *
     * - `single`: The user can select a single item.
     * - `multiple`: The user can select multiple items without using modifier keys.
     * - `extended`: The user can select multiple items by using modifier keys.
     *
     * @default "single"
     */
    selectionMode?: SelectionMode | undefined;
    /**
     * Function to scroll to a specific index
     */
    scrollToIndexFn?: ((details: ScrollToIndexDetails) => void) | undefined;
    /**
     * Whether to select the item when it is highlighted
     */
    selectOnHighlight?: boolean | undefined;
    /**
     * Whether to disallow empty selection
     */
    deselectable?: boolean | undefined;
    /**
     * Whether to enable typeahead on the listbox
     */
    typeahead?: boolean | undefined;
    /**
     * Function called when an item is selected
     */
    onSelect?: ((details: SelectionDetails) => void) | undefined;
}
type PropsWithDefault = "collection" | "selectionMode";
interface ListboxSchema<T extends CollectionItem = CollectionItem> {
    state: "idle";
    props: RequiredBy<ListboxProps<T>, PropsWithDefault>;
    context: {
        value: string[];
        highlightedValue: string | null;
        highlightedItem: T | null;
        selectedItemMap: Map<string, T>;
        focused: boolean;
    };
    computed: {
        hasSelectedItems: boolean;
        isTypingAhead: boolean;
        isInteractive: boolean;
        selection: Selection;
        multiple: boolean;
        selectedItems: T[];
        valueAsString: string;
    };
    refs: {
        typeahead: TypeaheadState;
        focusVisible: boolean;
        inputState: {
            autoHighlight: boolean;
            focused: boolean;
        };
    };
    action: string;
    guard: string;
    effect: string;
    event: EventObject;
}
type ListboxService<T extends CollectionItem = CollectionItem> = Service<ListboxSchema<T>>;
type ListboxMachine<T extends CollectionItem = CollectionItem> = Machine<ListboxSchema<T>>;
interface ItemProps<T extends CollectionItem = CollectionItem> {
    /**
     * The item to render
     */
    item: T;
    /**
     * Whether to highlight the item on hover
     */
    highlightOnHover?: boolean | undefined;
}
interface ItemState {
    /**
     * The underlying value of the item
     */
    value: string;
    /**
     * Whether the item is disabled
     */
    disabled: boolean;
    /**
     * Whether the item is selected
     */
    selected: boolean;
    /**
     * Whether the item is highlighted
     * @deprecated Use `focused` and `focusVisible` instead
     */
    highlighted: boolean;
    /**
     * Whether the item is focused
     */
    focused: boolean;
    /**
     * Whether the item is focus visible
     */
    focusVisible: boolean;
}
interface ItemGroupProps {
    id: string;
}
interface ItemGroupLabelProps {
    htmlFor: string;
}
interface InputProps {
    /**
     * Whether to automatically highlight the item when typing
     * @default false
     */
    autoHighlight?: boolean | undefined;
    /**
     * Determines how keyboard conflicts in the input are resolved.
     * - "caret": keep native text-editing behavior
     * - "navigate": forward supported keys to listbox navigation
     * @default "caret"
     */
    keyboardPriority?: "caret" | "navigate" | undefined;
}
interface ListboxApi<T extends PropTypes = PropTypes, V extends CollectionItem = CollectionItem> {
    /**
     * Whether the select value is empty
     */
    empty: boolean;
    /**
     * The value of the highlighted item
     */
    highlightedValue: string | null;
    /**
     * The highlighted item
     */
    highlightedItem: V | null;
    /**
     * Function to highlight a value
     */
    highlightValue: (value: string) => void;
    /**
     * Function to highlight the first value
     */
    highlightFirst: VoidFunction;
    /**
     * Function to highlight the last value
     */
    highlightLast: VoidFunction;
    /**
     * Function to highlight the next value
     */
    highlightNext: VoidFunction;
    /**
     * Function to highlight the previous value
     */
    highlightPrevious: VoidFunction;
    /**
     * Function to clear the highlighted value
     */
    clearHighlightedValue: VoidFunction;
    /**
     * The selected items
     */
    selectedItems: V[];
    /**
     * Whether there's a selected option
     */
    hasSelectedItems: boolean;
    /**
     * The selected item keys
     */
    value: string[];
    /**
     * The string representation of the selected items
     */
    valueAsString: string;
    /**
     * Function to select a value
     */
    selectValue: (value: string) => void;
    /**
     * Function to select all values.
     *
     * **Note**: This should only be called when the selectionMode is `multiple` or `extended`.
     * Otherwise, an exception will be thrown.
     */
    selectAll: VoidFunction;
    /**
     * Function to set the value of the select
     */
    setValue: (value: string[]) => void;
    /**
     * Function to clear the value of the select.
     * If a value is provided, it will only clear that value, otherwise, it will clear all values.
     */
    clearValue: (value?: string) => void;
    /**
     * Returns the state of a select item
     */
    getItemState: (props: ItemProps) => ItemState;
    /**
     * Function to toggle the select
     */
    collection: ListCollection<V>;
    /**
     * Whether the select is disabled
     */
    disabled: boolean;
    getInputProps: (props?: InputProps) => T["input"];
    getRootProps: () => T["element"];
    getLabelProps: () => T["label"];
    getValueTextProps: () => T["element"];
    getContentProps: () => T["element"];
    getItemProps: (props: ItemProps) => T["element"];
    getItemTextProps: (props: ItemProps) => T["element"];
    getItemIndicatorProps: (props: ItemProps) => T["element"];
    getItemGroupProps: (props: ItemGroupProps) => T["element"];
    getItemGroupLabelProps: (props: ItemGroupLabelProps) => T["element"];
}

export type { ElementIds, HighlightChangeDetails, InputProps, ItemGroupLabelProps, ItemGroupProps, ItemProps, ItemState, ListboxApi, ListboxMachine, ListboxProps, ListboxSchema, ListboxService, ScrollToIndexDetails, SelectionDetails, ValueChangeDetails };
