interface DropdownItem {
    /** Value of the selected item. */
    id?: string | number;
    /** Label for the selected item. */
    name?: string;
    /** Description of the item */
    title?: string;
    /** Icon of the item */
    image?: string;
    /** Name of the group where the item belongs to */
    group?: string;
    /** Keywords to help finding one item */
    synonym?: string[];
    /** Item is disabled */
    disabled?: boolean;
    /** Color for the item */
    color?: string;
}

interface Item {
    /** Value of the selected item. */
    id?: string | number;
    /** Description of the item */
    title?: string;
}

interface DropdownOptions {
    /** Endpoint to fetch data from a remote server */
    url?: string;
    /** Preloaded data items for the dropdown */
    data?: DropdownItem[];
    /** Format type of the data, typically { id: name } or { value: text } */
    format?: number;
    /** Indicates if multiple item selection is allowed */
    multiple?: boolean;
    /** Enables the autocomplete feature for user input */
    autocomplete?: boolean;
    /** Allows remote search for options */
    remoteSearch?: boolean;
    /** Enables the lazy loading feature for handling a large number of options */
    lazyLoading?: boolean;
    /** Rendering style of the dropdown: 'default', 'picker', or 'searchbar' */
    type?: 'default' | 'picker' | 'searchbar',
    /** Defines the dropdown's width */
    width?: number;
    /** Sets the maximum width of the dropdown */
    maxWidth?: number;
    /** Determines if the dropdown is opened when initialized */
    opened?: boolean;
    /** The initial value of the dropdown */
    value?: string;
    /** Placeholder text for the dropdown */
    placeholder?: string;
    /** Allows the user to add new options */
    newOptions?: boolean;
    /** Internal controller for the dropdown's position */
    position?: boolean;
    /** Event handler for value changes */
    onchange?: (el: HTMLElement, obj: Dropdown, oldValue: string, newValue: string) => void;
    /** Event handler for when the dropdown is ready */
    onload?: (el: HTMLElement, obj: Dropdown, data: any, val: any) => void;
    /** Event handler for when the dropdown opens */
    onopen?: (el: HTMLElement) => void;
    /** Event handler for when the dropdown closes */
    onclose?: (el: HTMLElement) => void;
    /** Event handler for when the dropdown receives focus */
    onfocus?: (el: HTMLElement) => void;
    /** Event handler for when the dropdown loses focus */
    onblur?: (el: HTMLElement) => void;
    /** Event handler for when a new option is added to the dropdown */
    oninsert?: (obj: Dropdown, item: DropdownItem, newItem: DropdownItem) => void;
    /** Event handler for just before a new option is added to the dropdown */
    onbeforeinsert?: (obj: Dropdown, item: DropdownItem) => void;
    /** Event handler for before a search on autocomplete is performed */
    onbeforesearch?: (obj: Dropdown, ajaxRequest: object) => boolean | null;
    /** Event handler for processing search results */
    onsearch?: (obj: Dropdown, result: object) => void;
    /** Toggles the sorting of dropdown elements */
    sortResults?: boolean;
    /** Indicates if the dropdown should automatically receive focus upon creation */
    autofocus?: boolean;
    /** Custom prompt on insert new items */
    prompt?: (addNewRow: (title: string, id: any) => void) => boolean;
    /** Allow toggle values on single dropdowns. Default: true */
    allowEmpty?: boolean;
}

interface ItemContainer {
    /** Data for the item */
    data: DropdownItem;
    /** HTML container for the element */
    element: HTMLElement;
    /** HTML container for the group */
    group: HTMLElement;
}

/** Toast Plugin */
export type Dropdown = (el: HTMLElement, options: DropdownOptions) => {
    /** Add a new item to the dropdown. */
    add: (title: string, id: string|number) => DropdownItem;
    /** Append new data to the dropdown */
    appendData: (data: DropdownItem[]) => void
    /** Close the dropdown picker */
    closeItem: (ignoreEvents?: boolean) => void
    /** Current selectIndex */
    currentIndex: number;
    /** Find the items with the keyword */
    find: (str: string) => void;
    /** Select the first item */
    first: () => void;
    /** Get all data */
    getData: () => DropdownItem[];
    /** Get the index position of a item by its value */
    getPosition: (value: string) => number | boolean;
    /** Get the text from the selected options */
    getText: (asArray?: boolean) => string | string[];
    /** Get the URL source for the data if defined */
    getUrl: () => string;
    /** Get the value from the selected options */
    getValue: (asArray?: boolean) => string | string[];
    /** DOM Elements for the groups */
    groups: HTMLElement[];
    /** DOM Element for the header */
    header: HTMLElement;
    /** Items */
    items: ItemContainer[];
    /** Move index to the last element in the dropdown */
    last: () => void;
    /** Internal lazy loading method */
    loadDown: () => void;
    /** Internal lazy loading method */
    loadFirst: () => void;
    /** Internal lazy loading method */
    loadLast: () => void;
    /** Internal lazy loading method */
    loadUp: () => void;
    /** Move index to the next element in the dropdown */
    next: () => void;
    /** Open the dropdown */
    open: () => void;
    /** Dropdown configuration */
    options: DropdownOptions;
    /** Move index to the previous element in the dropdown */
    prev: () => void;
    /** Reset the value of the dropdown */
    reset: () => void;
    /** Alias for setCursor */
    resetCursor: (index: number, setPosition?: boolean) => void
    /** Set the value to null */
    resetSelected: () => void;
    /** Array of results when filtering */
    results: DropdownItem[];
    /** Search term */
    search: string;
    /** Select an index */
    selectIndex: (index: number, force?: boolean) => void
    /** Select an item */
    selectItem: (item: DropdownItem) => void;
    /** Set the cursor to a specified element index */
    setCursor: (index: number, setPosition?: boolean) => void
    /** Set new data for the dropdown */
    setData: (items: DropdownItem[]) => void;
    /** Set the id or value for one item */
    setId: (item: number|DropdownItem, newId: number) => void;
    /** Change the dropdown options */
    setOptions: (newOptions: DropdownOptions, reset?: boolean) => void;
    /** Change the dropdown data from a URL */
    setUrl: (newUrl: string, callback?: Function) => void;
    /** Set the value for a dropdown */
    setValue: (newValue: string | string[]) => void;
    /** Internal type */
    type: 'dropdown';
    /** Alias for setCursor */
    updateCursor: (index: number, setPosition?: boolean) => void;
    /** Current internal value */
    value: Record<number, string>;
}
