import { MemoizedSelector } from '@ngrx/store';

type Comparer<T> = (a: T, b: T) => number;
type IdSelectorStr<T> = (model: T) => string;
type IdSelectorNum<T> = (model: T) => number;
type IdSelector<T> = IdSelectorStr<T> | IdSelectorNum<T>;
interface DictionaryNum<T> {
    [id: number]: T | undefined;
}
declare abstract class Dictionary<T> implements DictionaryNum<T> {
    [id: string]: T | undefined;
}
interface UpdateStr<T> {
    id: string;
    changes: Partial<T>;
}
interface UpdateNum<T> {
    id: number;
    changes: Partial<T>;
}
type Update<T> = UpdateStr<T> | UpdateNum<T>;
type Predicate<T> = (entity: T) => boolean;
type EntityMap<T> = (entity: T) => T;
interface EntityMapOneNum<T> {
    id: number;
    map: EntityMap<T>;
}
interface EntityMapOneStr<T> {
    id: string;
    map: EntityMap<T>;
}
type EntityMapOne<T> = EntityMapOneNum<T> | EntityMapOneStr<T>;
interface EntityState<T> {
    ids: string[] | number[];
    entities: Dictionary<T>;
}
interface EntityStateAdapter<T> {
    addOne<S extends EntityState<T>>(entity: T, state: S): S;
    addMany<S extends EntityState<T>>(entities: T[], state: S): S;
    setAll<S extends EntityState<T>>(entities: T[], state: S): S;
    setOne<S extends EntityState<T>>(entity: T, state: S): S;
    setMany<S extends EntityState<T>>(entities: T[], state: S): S;
    removeOne<S extends EntityState<T>>(key: string, state: S): S;
    removeOne<S extends EntityState<T>>(key: number, state: S): S;
    removeMany<S extends EntityState<T>>(keys: string[], state: S): S;
    removeMany<S extends EntityState<T>>(keys: number[], state: S): S;
    removeMany<S extends EntityState<T>>(predicate: Predicate<T>, state: S): S;
    removeAll<S extends EntityState<T>>(state: S): S;
    updateOne<S extends EntityState<T>>(update: Update<T>, state: S): S;
    updateMany<S extends EntityState<T>>(updates: Update<T>[], state: S): S;
    upsertOne<S extends EntityState<T>>(entity: T, state: S): S;
    upsertMany<S extends EntityState<T>>(entities: T[], state: S): S;
    mapOne<S extends EntityState<T>>(map: EntityMapOne<T>, state: S): S;
    map<S extends EntityState<T>>(map: EntityMap<T>, state: S): S;
}
type EntitySelectors<T, V> = {
    selectIds: (state: V) => string[] | number[];
    selectEntities: (state: V) => Dictionary<T>;
    selectAll: (state: V) => T[];
    selectTotal: (state: V) => number;
};
type MemoizedEntitySelectors<T, V> = {
    selectIds: MemoizedSelector<V, string[] | number[], (entityState: EntityState<T>) => string[] | number[]>;
    selectEntities: MemoizedSelector<V, Dictionary<T>, (entityState: EntityState<T>) => Dictionary<T>>;
    selectAll: MemoizedSelector<V, T[], (entityState: EntityState<T>) => T[]>;
    selectTotal: MemoizedSelector<V, number, (entityState: EntityState<T>) => number>;
};
interface EntityAdapter<T, IdType = string | number> extends EntityStateAdapter<T> {
    selectId: IdType extends string ? IdSelectorStr<T> : IdType extends number ? IdSelectorNum<T> : unknown;
    sortComparer: false | Comparer<T>;
    getInitialState(): EntityState<T>;
    getInitialState<S extends EntityState<T>>(state: Omit<S, keyof EntityState<T>>): S;
    getSelectors(): EntitySelectors<T, EntityState<T>>;
    getSelectors<V>(selectState: (state: V) => EntityState<T>): MemoizedEntitySelectors<T, V>;
}

/**
 * Creates an entity adapter with methods for managing collections of entities in state.
 *
 * @description
 * The entity adapter provides a set of predefined reducers and selectors for managing
 * normalized entity collections. It includes methods for adding, updating, removing,
 * and selecting entities from state.
 *
 * @template T - The entity type to be managed by the adapter
 *
 * @param options - Configuration options for the adapter
 * @param options.selectId - A function that selects the unique identifier from an entity.
 * Defaults to `(entity) => entity.id` if not provided.
 * @param options.sortComparer - A comparer function for sorting entities in state.
 * Set to `false` (default) to maintain insertion order, or provide a comparer function
 * to keep entities sorted.
 *
 * @returns An entity adapter containing methods for managing and selecting entity collections in state.
 *
 * @example
 * ```typescript
 * // Entity with default 'id' property
 * interface User {
 *   id: number;
 *   name: string;
 * }
 * const userAdapter = createEntityAdapter<User>();
 *
 * // Entity with custom id field
 * interface Book {
 *   isbn: string;
 *   title: string;
 * }
 * const bookAdapter = createEntityAdapter<Book>({
 *   selectId: (book) => book.isbn,
 * });
 *
 * // Entity with sorting
 * const sortedBookAdapter = createEntityAdapter<Book>({
 *   sortComparer: (a, b) => a.title.localeCompare(b.title),
 * });
 * ```
 */
declare function createEntityAdapter<T extends {
    id: string | number;
}>(options?: {
    sortComparer?: false | Comparer<T>;
}): EntityAdapter<T, T extends {
    id: infer U;
} ? U : never>;
declare function createEntityAdapter<T>(options: {
    selectId: IdSelectorStr<T>;
    sortComparer?: false | Comparer<T>;
}): EntityAdapter<T, string>;
declare function createEntityAdapter<T>(options: {
    selectId: IdSelectorNum<T>;
    sortComparer?: false | Comparer<T>;
}): EntityAdapter<T, number>;
declare function createEntityAdapter<T>(options: {
    selectId: IdSelector<T>;
    sortComparer?: false | Comparer<T>;
}): EntityAdapter<T>;
declare function createEntityAdapter<T>(): EntityAdapter<T>;

export { Dictionary, createEntityAdapter };
export type { Comparer, DictionaryNum, EntityAdapter, EntityMap, EntityMapOne, EntitySelectors, EntityState, IdSelector, MemoizedEntitySelectors, Predicate, Update };
