import { TimerOptions, Time } from 'timer-node';

declare class Dictionary<Type> {
    #private;
    constructor(data?: Record<string, Type>);
    /** Sets the value for the key */
    set(key: string, value: Type): this;
    /** Remove the value by the key */
    remove(key: string): this;
    /** Checks whether a value with a given key exists in the dictionary */
    has(key: string): boolean;
    /** Checks whether a value with a given key is missing from the dictionary */
    missing(key: string): boolean;
    /** Returns the value for the given key */
    get(key: string): Type | undefined;
    /** Returns a list of keys */
    keys(): string[];
    /** Creates a shallow copy of dictionary */
    clone(): Dictionary<Type>;
    /** Returns all data as a JS object */
    data(): Record<string, Type>;
}

type CollectionIterator = (value: any) => void;
declare class Collection<Type> {
    #private;
    constructor(items?: Type[]);
    /** Gets the first element of collection */
    first(iterator?: CollectionIterator): Type;
    /** Gets the last element of collection */
    last(predicate?: CollectionIterator): Type;
    /** Return the first element of the collection that meets the requirements */
    find(iterator: CollectionIterator): Type;
    /** Adds a new element to the end of the collection */
    add(data: Type): this;
    /** Gets a random element from collection */
    sample(): Type;
    /** Returns a new collection with all unique elements that are in both collections */
    intersects(collection: Collection<Type>): Collection<Type>;
    /** Returns a new collection with all unique elements that are in both collections, taking into account the specified requirements */
    intersectsBy(collection: Collection<Type>, iterator: CollectionIterator | string): Collection<Type>;
    /** Creates a slice of collection from start up to, but not including, end */
    slice(start?: number, end?: number): Collection<Type>;
    /** Returns the number of items in the collection */
    count(): number;
    /** Converts all elements in collection into a string separated by separator */
    join(separator: string): string;
    /** Gets the index at which the first occurrence of value is found in collection */
    indexOf(item: Type): number;
    /** Creates a duplicate-free version of a collection */
    uniq(): Collection<Type>;
    /** Creates a duplicate-free version of a collection according to requirements */
    uniqBy(iterator: CollectionIterator): Collection<Type>;
    /** Iterates over elements of collection, returning a collection of all elements that meets the requirements */
    filter(iterator: CollectionIterator): Collection<Type>;
    /** Iterates over elements of collection and invokes callback for each element */
    forEach(callback: (item: Type, index?: number) => Promise<void> | void): this;
    /** Removes all elements from collection that meets the requirements */
    remove(iterator: CollectionIterator): Collection<Type>;
    /** Combines elements from both collections into one */
    concat(collection: Collection<Type>): this;
    /** Returns `true` if the collection is empty */
    isEmpty(): boolean;
    /** Returns `true` if the collection is not empty */
    isNotEmpty(): boolean;
    /** Sorts the items in the collection alphabetically */
    sort(): Collection<Type>;
    /** Sorts collection items according to requirements */
    sortBy(iterators: CollectionIterator | CollectionIterator[], orders?: 'asc' | 'desc' | string[], natural?: boolean): this;
    /** Checks if value is in collection */
    includes(value: CollectionIterator): boolean;
    /** Checks whether a value is missing from the collection */
    missing(value: CollectionIterator): boolean;
    /** Creates a Dictionary composed of keys generated from the results of running each element of collection thru iterator */
    keyBy(iterator: CollectionIterator): Dictionary<Type>;
    /** Creates a Dictionary composed of keys generated from the results of running each element of collection thru iterator */
    groupBy(iterator: CollectionIterator): Dictionary<Type[]>;
    /** Creates a new Collection of values by running each element in collection thru iterator */
    map<Type>(iterator: (item: any) => Type): Collection<Type>;
    /** Creates a shallow copy of collection */
    clone(): Collection<Type>;
    /** Returns the underlying array represented by the collection */
    all(): Type[];
    /** Converts the collection into a JSON serialized string */
    toJSON(): string;
}

type LoggerOptions = {
    level: number;
};
declare class Logger {
    #private;
    constructor(options?: LoggerOptions);
    /** Outputs the object to the console as a tree structure */
    tree(object: object): void;
    mockTypes(cb: () => any): void;
    info(message: any, ...args: any[]): void;
    fail(message: any, ...args: any[]): void;
    trace(message: any, ...args: any[]): void;
    ready(message: any, ...args: any[]): void;
    debug(message: any, ...args: any[]): void;
    verbose(message: any, ...args: any[]): void;
    warn(message: any, ...args: any[]): void;
    log(message: any, ...args: any[]): void;
    error(message: any, ...args: any[]): void;
    start(message: any, ...args: any[]): void;
    success(message: any, ...args: any[]): void;
}

declare class Template {
    #private;
    constructor(template: string);
    /** Returns a list of all variables specified in the template */
    variables(): string[];
    /** Replaces variables in the template with values from the object with keys of the same name */
    format(obj: {
        [key: string]: string | number;
    }): string;
}

declare class Timer {
    #private;
    constructor(options?: TimerOptions);
    /** Starts the timer */
    start(): this;
    /** Pauses the timer */
    pause(): this;
    /** Resumes the timer */
    resume(): this;
    /** Stops the timer */
    stop(): this;
    /** Returns the elapsed time in milliseconds */
    ms(): number;
    /** Returns an object of time fractions (`d`, `h`, `m`, `s`, `ms`) */
    time(): Time;
    /** Formats the elapsed time using placeholders (`HH`, `mm`, `ss`, `ms`, etc.) */
    format(format: string): string;
}

export { Collection, Dictionary, Logger, Template, Timer };
export type { CollectionIterator, LoggerOptions };
