import * as _angular_core from '@angular/core';
import { OnChanges, OnDestroy, TemplateRef, SimpleChanges } from '@angular/core';
import { ConnectionPositionPair, ScrollStrategy } from '@angular/cdk/overlay';
import { TranslatableString } from '@siemens/element-translate-ng/translate';
import { Observable } from 'rxjs';
import * as i1 from '@siemens/element-ng/autocomplete';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

interface MatchSegment$1 {
    text: string;
    isMatching: boolean;
    matches: number;
    uniqueMatches: number;
}

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * A singular item to be used in the typeahead.
 * Can be either a string or an object.
 */
type TypeaheadOption = string | {
    [key in string | number]: any;
};
/**
 * An array of {@link TypeaheadOption}.
 */
type TypeaheadArray = TypeaheadOption[];
/**
 * An observable of a {@link TypeaheadArray} (array of {@link TypeaheadOption}).
 */
type TypeaheadObservable = Observable<TypeaheadArray>;
/**
 * Defines a source of options for the {@link SiTypeaheadDirective}.
 * Use it for server-side pre-filtering.
 *
 * This function will be called, whenever the search value is updated by the user.
 *
 * A loading indicator is shown when this function was called
 * until the Observable completes.
 *
 * @experimental
 */
type TypeaheadOptionSource = (search: string) => Observable<TypeaheadArray>;
/**
 * Either a {@link TypeaheadObservable} (observable of a {@link TypeaheadArray}) or a {@link TypeaheadArray}.
 */
type Typeahead = TypeaheadArray | TypeaheadObservable | TypeaheadOptionSource;
/**
 * A segment of a {@link TypeaheadMatch}, which is a matching or non-matching segment of a typeahead option.
 */
interface MatchSegment {
    text: string;
    isMatching: boolean;
    matches: number;
    uniqueMatches: number;
}
/**
 * A typeahead match, which is a processed typeahead option.
 */
interface TypeaheadMatch {
    option: TypeaheadOption;
    text: string;
    result: MatchSegment[];
    stringMatch: boolean;
    atBeginning: boolean;
    matches: number;
    uniqueMatches: number;
    uniqueSeparateMatches: number;
    matchesEntireQuery: boolean;
    matchesAllParts: boolean;
    matchesAllPartsSeparately: boolean;
    itemSelected?: boolean;
    iconClass?: string;
}
/**
 * An interface to define the context of a typeahead item template
 */
interface TypeaheadOptionItemContext {
    item: TypeaheadOption;
    index: number;
    match: TypeaheadMatch;
    query: string;
}

declare class SiTypeaheadDirective implements OnChanges, OnDestroy {
    protected static readonly overlayPositions: ConnectionPositionPair[];
    /**
     * Set the options of the typeahead.
     * Has to be either an Array or an Observable of an Array
     * of options (string or object)
     */
    readonly siTypeahead: _angular_core.InputSignal<Typeahead>;
    /**
     * Turns on/off the processing (searching and sorting) of the typeahead options.
     * Is used when searching and sorting is done externally.
     *
     * @defaultValue true
     */
    readonly typeaheadProcess: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * Makes the typeahead scrollable and sets its height.
     * Uses {@link typeaheadOptionsInScrollableView} and {@link typeaheadScrollableAdditionalHeight}.
     *
     * @defaultValue false
     */
    readonly typeaheadScrollable: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * If {@link typeaheadScrollable} is `true`, defines the number of items visible at once.
     *
     * @defaultValue 10
     */
    readonly typeaheadOptionsInScrollableView: _angular_core.InputSignal<number>;
    /**
     * Defines the maximum number of items added into the DOM. Default is 20 and 0 means unlimited.
     *
     * @defaultValue 20
     */
    readonly typeaheadOptionsLimit: _angular_core.InputSignal<number>;
    /**
     * If {@link typeaheadScrollable} is `true`, defines the number of additional pixels
     * to be added the the bottom of the typeahead to show users that it is scrollable.
     *
     * @defaultValue 13
     */
    readonly typeaheadScrollableAdditionalHeight: _angular_core.InputSignal<number>;
    /**
     * Defines the index of the item which should automatically be selected.
     *
     * @defaultValue 0
     */
    readonly typeaheadAutoSelectIndex: _angular_core.InputSignalWithTransform<number, unknown>;
    /**
     * Defines whether the typeahead can be closed using escape.
     *
     * @defaultValue true
     */
    readonly typeaheadCloseOnEsc: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * Defines whether the host value should be cleared when a value is selected.
     *
     * @defaultValue false
     */
    readonly typeaheadClearValueOnSelect: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * Defines the number of milliseconds to wait before displaying a typeahead after the host was
     * focused or a value inputted.
     *
     * @defaultValue 0
     */
    readonly typeaheadWaitMs: _angular_core.InputSignal<number>;
    /**
     * Defines the number of characters the value of the host needs to be before a typeahead is displayed.
     * Use `0` to have it display when focussing the host (clicking or tabbing into it).
     *
     * @defaultValue 1
     */
    readonly typeaheadMinLength: _angular_core.InputSignal<number>;
    /**
     * Defines the name of the field/property the option string is in when the typeahead options are objects.
     *
     * @defaultValue 'name'
     */
    readonly typeaheadOptionField: _angular_core.InputSignal<string>;
    /**
     * Defines whether multiselection of typeahead is possible with checkboxes.
     *
     * @defaultValue false
     */
    readonly typeaheadMultiSelect: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * Defines whether to tokenize the search or match the whole search.
     *
     * @defaultValue true
     */
    readonly typeaheadTokenize: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * Defines whether and how to require to match with all the tokens if {@link typeaheadTokenize} is enabled.
     * - `no` does not require all of the tokens to match.
     * - `once` requires all of the parts to be found in the search.
     * - `separately` requires all of the parts to be found in the search where there is not an overlapping different result.
     * - `independently` requires all of the parts to be found in the search where there is not an overlapping or adjacent different result.
     *  ('independently' also slightly changes sorting behavior in the same way.)
     *
     * @defaultValue 'separately'
     */
    readonly typeaheadMatchAllTokens: _angular_core.InputSignal<"no" | "once" | "separately" | "independently">;
    /**
     * Defines an optional template to use as the typeahead match item instead of the one built in.
     * Gets the {@link TypeaheadOptionItemContext} passed to it.
     */
    readonly typeaheadItemTemplate: _angular_core.InputSignal<TemplateRef<TypeaheadOptionItemContext> | undefined>;
    /**
     * Skip the sorting of matches.
     * If the value is `true`, the matches are sorted according to {@link SiTypeaheadSorting}.
     *
     * @defaultValue false
     */
    readonly typeaheadSkipSortingMatches: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * Screen reader only label for the autocomplete list.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_TYPEAHEAD.AUTOCOMPLETE_LIST_LABEL:Suggestions`)
     * ```
     */
    readonly typeaheadAutocompleteListLabel: _angular_core.InputSignal<TranslatableString>;
    /**
     * If set, the typeahead will at minium have the width of the connected input field.
     *
     * @defaultValue false
     */
    readonly typeaheadFullWidth: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /**
     * Optional CDK scroll strategy used for the typeahead overlay.
     * If not provided, no strategy is set explicitly and CDK will apply its default behavior.
     */
    readonly typeaheadScrollStrategy: _angular_core.InputSignal<ScrollStrategy | undefined>;
    /**
     * This option will be shown at the end of the typeahead.
     * Use it to allow users to create new options on the fly.
     *
     * Use the `{{ query }}` parameter in translation values to include the current text from the input.
     *
     * @experimental
     */
    readonly typeaheadCreateOption: _angular_core.InputSignal<TranslatableString | undefined>;
    /**
     * Emits an Event when the input field is changed.
     */
    readonly typeaheadOnInput: _angular_core.OutputEmitterRef<string>;
    /**
     * Emits an Event when a typeahead match is selected.
     * The event is a {@link TypeaheadMatch}
     */
    readonly typeaheadOnSelect: _angular_core.OutputEmitterRef<TypeaheadMatch>;
    /**
     * Emits an Event when a typeahead full match exists. A full match occurs when the entered text
     * is equal to one of the typeahead options.
     * The event is a {@link TypeaheadMatch}
     */
    readonly typeaheadOnFullMatch: _angular_core.OutputEmitterRef<TypeaheadMatch>;
    /** Emits whenever the typeahead overlay is opened or closed. */
    readonly typeaheadOpenChange: _angular_core.OutputEmitterRef<boolean>;
    /**
     * Emits when the create option is selected.
     * It will emit the current search query.
     *
     * @experimental
     */
    readonly typeaheadOnCreateOption: _angular_core.OutputEmitterRef<string>;
    /** @internal */
    readonly foundMatches: _angular_core.Signal<{
        itemSelected: any;
        iconClass: string | undefined;
        option: TypeaheadOption;
        text: string;
        result: MatchSegment$1[];
        stringMatch: boolean;
        atBeginning: boolean;
        matches: number;
        uniqueMatches: number;
        uniqueSeparateMatches: number;
        matchesEntireQuery: boolean;
        matchesAllParts: boolean;
        matchesAllPartsSeparately: boolean;
    }[] | TypeaheadMatch[] | {
        option: {
            text: string;
            option: TypeaheadOption;
        };
        text: string;
        result: {
            text: string;
            isMatching: boolean;
            matches: number;
            uniqueMatches: number;
        }[];
        itemSelected: any;
        iconClass: string | undefined;
        stringMatch: boolean;
        atBeginning: boolean;
        matches: number;
        uniqueMatches: number;
        uniqueSeparateMatches: number;
        matchesEntireQuery: boolean;
        matchesAllParts: boolean;
        matchesAllPartsSeparately: boolean;
        active: boolean;
    }[]>;
    /** @internal */
    readonly query: _angular_core.WritableSignal<string>;
    /**
     * Indicates whether the typeahead is shown.
     */
    get typeaheadOpen(): boolean;
    private overlay;
    private elementRef;
    private injector;
    private $typeahead;
    private componentRef?;
    private inputTimer;
    private sourceSubscription?;
    private matchSorter;
    private overlayRef?;
    private loadingSubscription?;
    /**
     * Indicates whether the typeahead is currently loading.
     * When using {@link TypeaheadOptionSource}, this is controlled by the `isLoading()` method
     * or automatically set to `true` while fetching options.
     *
     * @internal
     * @defaultValue false
     */
    readonly typeaheadLoading: _angular_core.WritableSignal<boolean>;
    /**
     * Indicates that the typeahead can be potentially open.
     * This signal is typically `true` when the input is focussed.
     * It may be overridden and set to `false` when escape is pressed
     * or when an option was selected.
     */
    private readonly canBeOpen;
    private readonly selectionCounter;
    private readonly typeaheadOptions;
    private readonly typeaheadSearch;
    private readonly processedSearch;
    private readonly unprocessedSearch;
    constructor();
    ngOnChanges(changes: SimpleChanges<this>): void;
    protected onBlur(): void;
    protected onInput(event: Event): void;
    protected onKeydownEscape(): void;
    ngOnDestroy(): void;
    /**
     * Handles TypeaheadOptionSource by subscribing to query changes and fetching options.
     * Manages loading state automatically or uses custom isLoading() observable if provided.
     */
    private handleTypeaheadOptionSource;
    private loadComponent;
    /**
     * Extracts the display value from a typeahead option.
     *
     * For string options, returns the string value directly.
     * For object options, returns the value of the field specified by {@link typeaheadOptionField}
     * (defaults to 'name'), or an empty string if the field doesn't exist.
     *
     * @param option - The typeahead option to extract the value from
     * @returns The string representation of the option for display purposes
     */
    private getOptionValue;
    /**
     * Extracts a specific field value from a typeahead option.
     *
     * This method is used to access additional properties of object-type options,
     * such as 'selected' for multi-select functionality or 'iconClass' for displaying icons.
     *
     * @param option - The typeahead option to extract the field from
     * @param field - The name of the field to extract
     * @returns The field value as a string if the option is an object and the field exists,
     *          otherwise undefined
     */
    private getOptionField;
    /** @internal */
    createOption(): void;
    /** @internal */
    selectMatch(match: TypeaheadMatch): void;
    private removeComponent;
    private clearTimer;
    private escapeRegex;
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SiTypeaheadDirective, never>;
    static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SiTypeaheadDirective, "[siTypeahead]", ["si-typeahead"], { "siTypeahead": { "alias": "siTypeahead"; "required": true; "isSignal": true; }; "typeaheadProcess": { "alias": "typeaheadProcess"; "required": false; "isSignal": true; }; "typeaheadScrollable": { "alias": "typeaheadScrollable"; "required": false; "isSignal": true; }; "typeaheadOptionsInScrollableView": { "alias": "typeaheadOptionsInScrollableView"; "required": false; "isSignal": true; }; "typeaheadOptionsLimit": { "alias": "typeaheadOptionsLimit"; "required": false; "isSignal": true; }; "typeaheadScrollableAdditionalHeight": { "alias": "typeaheadScrollableAdditionalHeight"; "required": false; "isSignal": true; }; "typeaheadAutoSelectIndex": { "alias": "typeaheadAutoSelectIndex"; "required": false; "isSignal": true; }; "typeaheadCloseOnEsc": { "alias": "typeaheadCloseOnEsc"; "required": false; "isSignal": true; }; "typeaheadClearValueOnSelect": { "alias": "typeaheadClearValueOnSelect"; "required": false; "isSignal": true; }; "typeaheadWaitMs": { "alias": "typeaheadWaitMs"; "required": false; "isSignal": true; }; "typeaheadMinLength": { "alias": "typeaheadMinLength"; "required": false; "isSignal": true; }; "typeaheadOptionField": { "alias": "typeaheadOptionField"; "required": false; "isSignal": true; }; "typeaheadMultiSelect": { "alias": "typeaheadMultiSelect"; "required": false; "isSignal": true; }; "typeaheadTokenize": { "alias": "typeaheadTokenize"; "required": false; "isSignal": true; }; "typeaheadMatchAllTokens": { "alias": "typeaheadMatchAllTokens"; "required": false; "isSignal": true; }; "typeaheadItemTemplate": { "alias": "typeaheadItemTemplate"; "required": false; "isSignal": true; }; "typeaheadSkipSortingMatches": { "alias": "typeaheadSkipSortingMatches"; "required": false; "isSignal": true; }; "typeaheadAutocompleteListLabel": { "alias": "typeaheadAutocompleteListLabel"; "required": false; "isSignal": true; }; "typeaheadFullWidth": { "alias": "typeaheadFullWidth"; "required": false; "isSignal": true; }; "typeaheadScrollStrategy": { "alias": "typeaheadScrollStrategy"; "required": false; "isSignal": true; }; "typeaheadCreateOption": { "alias": "typeaheadCreateOption"; "required": false; "isSignal": true; }; }, { "typeaheadOnInput": "typeaheadOnInput"; "typeaheadOnSelect": "typeaheadOnSelect"; "typeaheadOnFullMatch": "typeaheadOnFullMatch"; "typeaheadOpenChange": "typeaheadOpenChange"; "typeaheadOnCreateOption": "typeaheadOnCreateOption"; }, never, never, true, [{ directive: typeof i1.SiAutocompleteDirective; inputs: {}; outputs: {}; }]>;
}

declare class SiTypeaheadItemTemplateDirective {
    static ngTemplateContextGuard(dir: SiTypeaheadItemTemplateDirective, ctx: any): ctx is TypeaheadOptionItemContext;
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SiTypeaheadItemTemplateDirective, never>;
    static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SiTypeaheadItemTemplateDirective, "[siTypeaheadItemTemplate]", never, {}, {}, never, never, true, never>;
}

declare class SiTypeaheadModule {
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SiTypeaheadModule, never>;
    static ɵmod: _angular_core.ɵɵNgModuleDeclaration<SiTypeaheadModule, never, [typeof SiTypeaheadDirective, typeof SiTypeaheadItemTemplateDirective], [typeof SiTypeaheadDirective, typeof SiTypeaheadItemTemplateDirective]>;
    static ɵinj: _angular_core.ɵɵInjectorDeclaration<SiTypeaheadModule>;
}

export { SiTypeaheadDirective, SiTypeaheadItemTemplateDirective, SiTypeaheadModule };
export type { MatchSegment, Typeahead, TypeaheadArray, TypeaheadMatch, TypeaheadObservable, TypeaheadOption, TypeaheadOptionItemContext, TypeaheadOptionSource };
