import { EventEmitter } from 'events'

declare interface Options {
  name: String;
  ttl?: Number;
}

declare interface CollectionEvents {
  expired: [Object];
  ttl: [Boolean];
  ready: [];
}

declare class Collection extends EventEmitter {
  constructor(db: BaseDatabase, options: Options);

  public db: BaseDatabase;
  public displayName: String;
  public size: Number;
  public isOpen: Boolean;

  public set(data: Object, filter: Object): Promise<Boolean>;
  public delete(filter: Object, limit: Number): Promise<Boolean>;
  public findOne(filter: Object): Promise<Object>;
  public find(filter: Object, limit: Number): Promise<Object[]>;
  public update(filter: Object, property: String[], value: any, object?: Boolean): Promise<Boolean>;
  public deleteMany(...filters: Object[]): Promise<Boolean>;

  public on<K extends keyof CollectionEvents>(event: K, listener: (...args: CollectionEvents[K]) => void): this;
  public on<S extends string | symbol>(
    event: Exclude<S, keyof CollectionEvents>,
    listener: (...args: any[]) => void,
  ): this;

  public once<K extends keyof CollectionEvents>(event: K, listener: (...args: CollectionEvents[K]) => void): this;
  public once<S extends string | symbol>(
    event: Exclude<S, keyof CollectionEvents>,
    listener: (...args: any[]) => void,
  ): this;

  public emit<K extends keyof CollectionEvents>(event: K, ...args: CollectionEvents[K]): boolean;
  public emit<S extends string | symbol>(event: Exclude<S, keyof CollectionEvents>, ...args: any[]): boolean;

  public off<K extends keyof CollectionEvents>(event: K, listener: (...args: CollectionEvents[K]) => void): this;
  public off<S extends string | symbol>(
    event: Exclude<S, keyof CollectionEvents>,
    listener: (...args: any[]) => void,
  ): this;

  public removeAllListeners<K extends keyof CollectionEvents>(event?: K): this;
  public removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof CollectionEvents>): this;
}

declare class BaseDatabase extends EventEmitter {
  constructor(name: String);

  public displayName: String;
  public isReady: Boolean;

  public collection(options: Options): Collection;

  public on(event: 'ready', listener: (...args: []) => void): this;
  public on<S extends string | symbol>(
	event: Exclude<S, 'ready'>,
	listener: (...args: any[]) => void
  ): this;

  public once(event: 'ready', listener: (...args: any[]) => void): this;
  public once<S extends string | symbol>(
	event: Exclude<S, 'ready'>,
	listener: (...args: any[]) => void
  ): this;

  public emit(event: 'ready', ...args: any[]): this;
  public emit<S extends string | symbol>(event: Exclude<S, 'ready'>, ...args: any[]): this;

  public off(event: 'ready', listener: (...args: []) => void): this;
  public off<S extends string | symbol>(
	event: Exclude<S, 'ready'>,
	listener: (...args: any[]) => void
  ): this;

  public emit(event?: 'ready'): this;
  public emit<S extends string | symbol>(event?: Exclude<S, 'ready'>): this;
}

declare module 'dbd.db' {
  function database(name: String): BaseDatabase;

  export = database

  export function deprecated(dbName: String, collection: String): Promise<Boolean>;

  export const version: string;
}