import { EventEmitter } from "events";

declare type secretTokens = {
  spotify?: {
    client_id?: string | number;
    client_secret?: string | number;
    refresh_token?: string | number;
    market?: string | "US";
  };
  soundcloud?: { client_id?: string | number };
};

declare type fetchOptions = {
  tokens?: secretTokens;
  fetchLimit?: number;
  streamQuality?: string;
  rawCookies?: string;
  userAgents?: string[];
  skipAlbumLimit?: Boolean;
};

export type scrapperOptions = {
  fetchLyrics?: boolean | true;
  eventReturn?: { metadata?: any };
  ratelimit?: number;
  ignoreInternalError?: boolean | true;
  fetchOptions?: fetchOptions;
  streamDownload?: boolean | false;
  playersCompatibility?: boolean | false;
  waitForPromise?: Boolean | true;
};

export class queue extends EventEmitter {
  public constructor(
    rawQuer: String,
    __scrapperOptions: scrapperOptions,
    playdl: Object
  );
  public readonly creationTime: Number;
  public readonly id: String;
  public readonly tracks: Track[];
  public readonly album: Album | Boolean;
  public readonly totalTracks: Number | 0;
  public readonly destroyed: Boolean | false;
  public readonly stopped: Boolean | false;
  public readonly completedTracks: Number;
  get raw(): {
    totalTracks?: Number | 0;
    rawQuery?: String;
    options?: scrapperOptions;
    playdl?: Object;
    status?: Number | 0;
  };
  get completed(): Boolean;
  get tracksCount(): Number;
  get rawQuery(): String;
  get playdl(): Object;
  get options(): scrapperOptions;
  public filter(): Boolean;
  public destroy(deleteCaches?: Boolean | true): Boolean;
  public stop(): Boolean;
  public on<K extends keyof extractorDataEvents>(
    event: K,
    listener: (...args: extractorDataEvents[K]) => Awaitable<void>
  ): this;
  public on<S extends string | symbol>(
    event: Exclude<S, keyof extractorDataEvents>,
    listener: (...args: any[]) => Awaitable<void>
  ): this;
}

export class Track {
  get playdl(): Object;
  public readonly __scrapperOptions: scrapperOptions;
  public getStream(
    extraStream?: string,
    ignoreStreamError?: boolean,
    reTryonRatelimit?: boolean | true,
    assignStream?: Boolean | true
  ): Promise<Track | object> | undefined;
  public getLyrics(): Promise<string>;
  public get album(): Album;
  readonly trackId: number;
  readonly uniqueId: string;
  readonly url: string;
  readonly videoId: string | number;
  readonly title: string;
  readonly description: string;
  readonly author: { name: string; url: string };
  readonly extractorModel: {
    orignal:
      | string
      | "deezer"
      | "youtube"
      | "spotify"
      | "facebook"
      | "reverbnation"
      | "soundcloud"
      | "arbitary";
    custom: string | "play-dl";
  };
  readonly duration: {
    ms: number;
    readable: string;
  };
  readonly thumbnail: {
    Id: string | number;
    url: string;
  };
  readonly channel: {
    name: string;
    Id: string | number;
    url: string;
  };
  readonly isLive: boolean;
  readonly ratings: {
    likes: number | string;
    dislikes: number | string;
  };
  readonly stream: {
    buffer:
      | string
      | ReadableStream<Buffer>
      | "Fetched Stream from play-dl using stream() function or ffmpeg parsed Stream Url";
    videoUrl: string;
    type: string;
    duration: {
      ms: number;
      readable: string;
    };
    videoId: string | number;
  };
  readonly queue: queue;
  metadata: any;
  readonly lyrics:
    | string
    | ""
    | "Lyrics fetched from Un-Official Source , so limited Resources are expected";
  readonly raw: {} | "Unparsed and fetched Track Data from play-dl";
}

export class Album {
  public get tracks(): Track[];
  readonly id: Number | String | undefined;
  readonly name: String;
  readonly url: String;
  readonly description: String;
  readonly thumbnail: String;
  readonly tracksCount: Number;
  readonly channel:
    | {
        name: String;
        description: String;
        url: String;
        thumbnail: String;
      }
    | undefined;
  readonly views: Number;
  readonly queue: queue;
  readonly uniqueId: string;
  metadata: any;
}

export type Awaitable<T> = T | PromiseLike<T>;

export interface playdlEvents {
  queue: [queue];
  track: [
    orignal_extractor:
      | string
      | "deezer"
      | "youtube"
      | "spotify"
      | "facebook"
      | "reverbnation"
      | "soundcloud"
      | "arbitary",
    album: Album,
    track: Track,
    queue: queue,
    metadata: any
  ];
  tracks: [tracks: Track[], album: Album, queue: queue, metadata: any];
  album: [Album: Album, queue: queue, metadata: any];
}

export interface extractorDataEvents {
  track: [
    orignal_extractor:
      | string
      | "deezer"
      | "youtube"
      | "spotify"
      | "facebook"
      | "reverbnation"
      | "soundcloud"
      | "arbitary",
    album: Album,
    track: Track,
    metadata: any
  ];
  tracks: [tracks: Track[], album: Album, metadata: any];
  album: [Album];
}
