import { AlStopwatch } from '@al/core';

/**
 *  This interfaces describes an active filter
 */
export declare interface AlCardstackActiveFilter<EntityType = any, PropertyType extends AlCardstackItemProperties = any> {
    property: AlCardstackPropertyDescriptor;
    propField: string;
    values: AlCardstackValueDescriptor[];
    rawValues: any[];
    /**
     *  The default callback will return true ("match") if any of the values in the filter match a given entity's value for that field, but it can be overridden to provide custom logic.
     */
    callback: {
        (entity: EntityType, properties: PropertyType, filter: AlCardstackActiveFilter<EntityType, PropertyType>): boolean;
    };
}

/**
 *  Describes an aggregation descriptor for a given cardstack.  An aggregation descriptor is just a nested
 *  dictionary of properties -> values -> total counts.  If a given item is `null` rather than a number, that
 *  indicates that the UI should calculate the aggregation dynamically on the client side.
 */
export declare interface AlCardstackAggregations {
    properties: {
        [property: string]: {
            [value: string]: number | null;
        };
    };
}

/**
 *  Describes the general characteristics of a given cardstack view.
 */
export declare interface AlCardstackCharacteristics {
    /**
     *  Describees the principal entity being described inside a cardstack (e.g., "Scheduled Reports" or "Observations")
     */
    entity: AlCardstackPropertyDescriptor;
    /**
     *  Identifies a set of properties (referenced by ID) that the cardstack's content can be grouped by.
     *  An empty array indicates that grouping is not supported for this cardstack and the group by selector should not be shown.
     */
    groupableBy: (string | AlCardstackPropertyDescriptor)[];
    sortableBy: (string | AlCardstackPropertyDescriptor)[];
    /**
     *  Identifies a set of properties (referenced by ID) that the cardstack's content can be filtered by.
     *  An empty array indicates that filtering is not supported for this cardstack, and the filter panel should not be shown.
     */
    filterableBy: (string | AlCardstackPropertyDescriptor)[];
    /**
     *  Identifiers which properties in the DTO text searches should be applied against.
     *  NOTE: complex obj are not supported.  If 'remoteSearch' is true, these values will be ignored.
     */
    searchableBy?: string[];
    /**
     * If provided, indicates that the cards should be grouped into distinct sections based on a given attribute.
     * The captionPlural property of the property descriptor will be used as the header for each section.
     */
    sectionBy?: string | AlCardstackPropertyDescriptor;
    /**
     * A dictionary of property definitions referenced above.
     */
    definitions: {
        [propertyId: string]: AlCardstackPropertyDescriptor;
    };
    /**
     * If true, indicates that the client should read all available data aggressively.  This is useful for views/entities where aggregation
     * cannot be provided service side and must be tabulated dynamically in the client.
     */
    greedyConsumer: boolean;
    /**
     * For filters with many values, these specify the maximum initial list size per filter
     * and the number of additional items that should be exposed with each press of "Show More"
     */
    filterValueLimit: number;
    filterValueIncrement: number;
    /**
     * If true, indicates that filter values with no matching results should be hidden from the filter list.
     */
    hideEmptyFilterValues: boolean;
    /**
     * If true, pagination will be executed locally
     */
    localPagination: boolean;
    /**
     * If true, search will be executed remotely (changes to search value will reload the view).  Otherwise, `searchableBy` will
     * be used to determine which entity properties the textual filter should be applied against.
     */
    remoteSearch: boolean;
}

/**
 *  Describes a cardstack item, representing a single entity inside the view.
 *  This simple wrapper object contains a caption, a handful of common properties (referenced by the cardstack's characteristics), and
 *  a blob referencing the underlying entity data.
 */
export declare interface AlCardstackItem<EntityType = any, PropertyType extends AlCardstackItemProperties = any> {
    /**
     * Each item has a unique identifier, although the format may vary by entity type or even be mixed across systems
     */
    id: string;
    /**
     * Textual caption (h1/title)
     */
    caption: string;
    /**
     * Indicates whether or not the given item is visible/displayed
     */
    visible?: boolean;
    /**
     * Indicates whether or not the given item is opened/expanded
     */
    expanded?: boolean;
    /**
     * Indicates which segment the data belongs to, if any
     */
    segment?: AlCardstackValueDescriptor;
    /**
     * Filterable/groupable/sortable properties
     */
    properties: PropertyType;
    /**
     * A reference to the minimial view of the underlying entity (e.g., incident, scheduled_report, observation, etc)
     */
    entity: EntityType;
    /**
     * Indicates whether or not the given item is checked
     */
    checked?: boolean;
}

/**
 * This is just a placeholder interface for whatever indexable properties a particular entity has.
 */
export declare interface AlCardstackItemProperties {
    id: string;
    caption: string;
}

/**
 *  Describes a page of items for display in a cardstack
 */
export declare interface AlCardstackPage<EntityType = any> {
    items: AlCardstackItem<EntityType>;
    continuation_token?: string;
    pages_remaining: number;
}

/**
 * This is an abstract description of a property.  Many of the individual properties may be omitted from a given instance.
 */
export declare interface AlCardstackPropertyDescriptor {
    domain?: string;
    property: string;
    caption: string;
    captionPlural?: string;
    description?: string;
    values: AlCardstackValueDescriptor[];
    multiSelect?: boolean;
    autoIndex?: boolean;
    remote?: boolean;
    activeFilter?: boolean;
    metadata: {
        [property: string]: any;
    };
    sortPositionIndex?: number;
    avoidReduce?: boolean;
}

/**
 *  A collection of abstract types to facilitate the most common view in the Alert Logic UI world,
 *  the infinite scroll + filters card list.
 *
 *  For the sake of giving these types a common and somewhat unique namespace, these types will refer to them
 *  as a "cardstack", and all types will be prefixed with AlCardstack.
 *
 *  Author: Big Orange Geek <knielsen@alertlogic.com>
 *  Copyright 2019 but almost 2020 Alert Logic, Inc.
 */
/**
 * Describes a specific property value.  Only necessary for values that can be filtered on.
 */
export declare interface AlCardstackValueDescriptor {
    property: string;
    value: any;
    caption: string;
    captionPlural: string;
    valueKey: string;
    default?: boolean;
    activeFilter?: boolean;
    count?: number;
    total?: number;
    prefilterCount?: number;
    type?: string;
    sort?: number;
    metadata?: {
        [property: string]: unknown;
    };
}

/**
 *  Manages a cardstack view state
 */
export declare abstract class AlCardstackView<EntityType = any, PropertyType extends AlCardstackItemProperties = any, CharacteristicsType extends AlCardstackCharacteristics = AlCardstackCharacteristics> {
    characteristics?: CharacteristicsType;
    loading: boolean;
    itemsPerPage: number;
    continuation: string | undefined;
    loadedPages: number;
    remainingPages: number;
    rawCards: AlCardstackItem<EntityType>[];
    filteredCards: AlCardstackItem<EntityType>[];
    cards: AlCardstackItem<EntityType>[];
    visibleCards: number;
    textFilter: string | RegExp | null;
    groupingBy: AlCardstackPropertyDescriptor | null;
    sortingBy: AlCardstackPropertyDescriptor | null;
    sortOrder: 'asc' | 'desc';
    dateRange: Date[] | number[];
    checked: boolean;
    activeFilters: AlCardstackActiveFilter<EntityType, PropertyType>[];
    autoIndexProperties: AlCardstackPropertyDescriptor[];
    autoDefineCardsChanged: boolean;
    error?: string | Error | any;
    aggregations: AlCardstackAggregations;
    reduceFilters: {
        [property: string]: string[];
    };
    protected filtersChanged: AlStopwatch;
    constructor(characteristics?: CharacteristicsType);
    /**
     * Starts loading the view and digesting data
     */
    start(): Promise<void>;
    updateCharacteristics(characteristics: AlCardstackCharacteristics): void;
    /** set the first page of the filteredCards */
    startPagination(filteredCards: {
        properties: PropertyType;
        entity: EntityType;
        id: string;
        caption: string;
    }[]): void;
    /**
     * Starts loading next batch data into view
     */
    continue(): Promise<void>;
    /**
     * calculate the remaining pages
     * @param total items
     */
    resetPagination(total: number): void;
    getProperty(propertyId: string | AlCardstackPropertyDescriptor): AlCardstackPropertyDescriptor;
    getValue(propertyId: string | AlCardstackPropertyDescriptor, value: any): AlCardstackValueDescriptor;
    applyFiltersAndSearch(): void;
    /**
     *  Applies a textual search filter to all properties/entities in the current list, or clears the current filter if `filterPattern` is null.
     *  This should cause the `visibleItem` count to be recalculated, possibly triggering a load of further pages of data.
     */
    applyTextFilter(filterPattern: string | RegExp | null): void;
    /**
     *  Applies grouping logic to the current view, or clears grouping if `property` is null.
     */
    applyGroupingBy(descriptor: AlCardstackPropertyDescriptor | null): boolean;
    /**
     *  Applies sorting logic to the current view, or restores default if `property` is null.
     *  This is the default implementation, which can be called if the deriving class doesn't implement OR wants to call into the super class.
     */
    applySortBy(pDescriptor: AlCardstackPropertyDescriptor, order?: string): void;
    /**
     *  Applies a filter to the current view, optionally specifying a custom filter callback.
     */
    applyFilterBy(vDescriptor: AlCardstackValueDescriptor, resetActiveFilters?: boolean, callback?: {
        (entity: EntityType, properties: PropertyType, filter: AlCardstackActiveFilter<EntityType, PropertyType>): boolean;
    }): boolean;
    /**
     *  Applies multiple filter to the current view, optionally specifying a custom filter callback.
     */
    applyMultipleFilterBy(vDescriptors: AlCardstackValueDescriptor[], resetActiveFilters?: boolean, callback?: {
        (entity: EntityType, properties: PropertyType, filter: AlCardstackActiveFilter<EntityType, PropertyType>): boolean;
    }): void;
    /**
     *  Removes a filter from the current view.
     */
    removeFilterBy(vDescriptor: AlCardstackValueDescriptor): boolean;
    clearFilters(): void;
    markCardsAsCheck(): void;
    /**
     * Allows to mark the all cards as checked or unchecked
     * @param checked
     */
    applySelect(checked: boolean): void;
    /**
     *  Retrieves the next page of items using the current group/sort criteria.  The derived class must provide an implementation of this method,
     *  and it should set the `remainingPages` value when it completes execution.
     *
     *  The second parameter describes any active filters whose properties indicate that they will be applied externally (either in an API call or external
     *  filtration layer).
     */
    abstract fetchData(initialLoad: boolean, remoteFilters: AlCardstackActiveFilter[]): Promise<EntityType[]>;
    /**
     *  Given an entity instance, allows the deriving class to populate a properties object -- which may be correlated or extracted or mapped as necessary
     *  from other data -- that can be used to sort, filter, group, and segment by.
     */
    abstract deriveEntityProperties(entity: EntityType): PropertyType;
    /**
     *  Optional method to notify when we make changes in the card list
     *  It call every time the something happend with the list
     */
    onCardsChanged?(): void;
    /**
     *  Optional method to respond when new property values are discovered
     */
    onFiltersChanged?(): void;
    /**
     *  Optional method to generate characteristics asynchronously, after constructor has executed.
     */
    generateCharacteristics?(): Promise<CharacteristicsType>;
    /**
     *  Optional method to automatically index unrecognized property values
     */
    decoratePropertyValue?(entity: EntityType, property: AlCardstackPropertyDescriptor, value: AlCardstackValueDescriptor): any;
    /**
     * Sets the active filters based on the specified query parameters.
     * This function is useful when using deep links.
     *
     * @param {Object} params - The query parameters object.
     * @throws {Error} If `characteristics` is not configured, an error will be thrown.
     * @returns {void}
     */
    setDefaultFiltersByParams(params: {
        [key: string]: string;
    }): void;
    /**
     * Protected Internal Methods
     */
    protected recalculateFilterTotals(): void;
    protected recalculateFilterActivation(): void;
    protected addNextSection(newData: AlCardstackItem<EntityType, PropertyType>[]): void;
    protected ingest(entities: EntityType[]): AlCardstackItem<EntityType>[];
    /**
     * This is the default filter evaluator.
     */
    protected defaultFilterCb(entity: EntityType, properties: PropertyType, filter: AlCardstackActiveFilter<EntityType, PropertyType>, data?: any): boolean;
    /**
     *  Method to determine visibility of an individual card item based on the current set of active filters.
     */
    protected evaluateCardVisibilityByFilter(card: AlCardstackItem<EntityType, PropertyType>): boolean;
    /**
     *  Method to determine visibility of an individual card item based on the current search text
     */
    protected evaluateCardVisibilityBySearch(card: AlCardstackItem<EntityType, PropertyType>, search: string | RegExp | null): boolean;
    protected evaluateCardState(card: AlCardstackItem<EntityType, PropertyType>): boolean;
    /**
     *  Utility method to normalize and validate an input characteristics definitions, and then store it
     *  to the instance's `characteristics` property.
     */
    protected normalizeCharacteristics(characteristics: CharacteristicsType): void;
    protected resolveDescriptor(descriptor: string | AlCardstackPropertyDescriptor): AlCardstackPropertyDescriptor;
    protected getRemoteFilters(): AlCardstackActiveFilter<EntityType, PropertyType>[];
    /**
     * Updates the list of active filters based on the provided value descriptor.
     *
     * @param {AlCardstackValueDescriptor} vDescriptor - The value descriptor to apply as a filter.
     * @param {boolean} [resetActiveFilters=false] - If true, clears all filters in the same category as the one being applied, leaving only the new filter active.
     * @param {function} [callback] - An optional callback function to be called when the filter is applied.
     * @returns {void}
     */
    protected updateActiveFilters(vDescriptor: AlCardstackValueDescriptor, resetActiveFilters?: boolean, callback?: {
        (entity: EntityType, properties: PropertyType, filter: AlCardstackActiveFilter<EntityType, PropertyType>): boolean;
    }): void;
    /**
     * Fill the property name of the variable reduceFilter with filterable fields
     */
    private fillPropertiesReduceFilters;
}

export { }
