import { Readable } from 'stream';
import * as gaxios from 'gaxios';

type Slug = {
    type: OtakuSlugType;
    slug: string;
};
type OtakuSlugType = 'anime' | 'episode' | 'batch' | 'lengkap';
declare const resolveSlug: (url: string) => Slug | undefined;

type util_Slug = Slug;
declare const util_resolveSlug: typeof resolveSlug;
declare namespace util {
  export {
    util_Slug as Slug,
    util_resolveSlug as resolveSlug,
  };
}

type Genre = {
    name: string;
    url: string;
};
type AnimeStatus = 'ongoing' | 'completed' | 'unknown';
type EpisodeResolution = '240p' | '360p' | '480p' | '720p' | '1080p';
type SearchResult = {
    name: string;
    image: string;
    genres: Genre[];
    url: string;
    rating?: number;
    status: AnimeStatus;
    getSlug?: () => Slug | undefined;
};
type AnimeInformation = Exclude<SearchResult, 'getSlug'> & {
    synopsis: string;
    japaneseName: string;
    type: string;
    totalEpisodes: number;
    duration: string;
    studio: string;
    releasedAt: Date;
    producers: string;
    episodes: Array<{
        title: string;
        url: string;
        uploadedAt: Date;
    }>;
};
type Batch = Pick<AnimeInformation, 'name' | 'totalEpisodes' | 'duration' | 'producers' | 'rating' | 'japaneseName' | 'studio' | 'url'> & Pick<Episode, 'credit' | 'downloads'> & {
    aired: Date;
    genres: string[];
};
type Episode = {
    title: string;
    postedBy: string;
    /**
     * Local time
     */
    releasedTime: string;
    url: string;
    downloads: Array<{
        resolution: EpisodeResolution;
        size: string;
        urls: Array<{
            source: string;
            url: string;
        }>;
    }>;
    credit: string;
    picture: string;
    mirrors: Array<{
        getNonceCode: () => Promise<string>;
        getMirrorUrl: () => Promise<string | undefined>;
        getStreamFileSize: () => Promise<number | undefined>;
        getStreamUrl: () => Promise<string | undefined>;
        stream: () => Promise<Readable>;
        resolution: string;
        source: string;
        _encoded: string;
    }>;
};
type Day = 'senin' | 'selasa' | 'rabu' | 'kamis' | 'jumat' | 'sabtu' | 'minggu' | 'random';
type Schedule = {
    day: Day;
    animes: Array<Pick<SearchResult, 'name' | 'url'>>;
    slug?: Slug;
};

type types_AnimeInformation = AnimeInformation;
type types_AnimeStatus = AnimeStatus;
type types_Batch = Batch;
type types_Day = Day;
type types_Episode = Episode;
type types_EpisodeResolution = EpisodeResolution;
type types_Genre = Genre;
type types_Schedule = Schedule;
type types_SearchResult = SearchResult;
declare namespace types {
  export {
    types_AnimeInformation as AnimeInformation,
    types_AnimeStatus as AnimeStatus,
    types_Batch as Batch,
    types_Day as Day,
    types_Episode as Episode,
    types_EpisodeResolution as EpisodeResolution,
    types_Genre as Genre,
    types_Schedule as Schedule,
    types_SearchResult as SearchResult,
  };
}

/**
 * @class Odesus
 */
declare class Odesus {
    client: gaxios.Gaxios;
    /**
     * @constructor
     * @param baseUrl Otakudesu Base URL
     */
    constructor(baseUrl?: string);
    /**
     * Search animes
     * @param query Search query
     * @return {SearchResult[]}
     */
    search(query: string): Promise<SearchResult[]>;
    /**
     * Get anime information
     * @param {Slug} slug Anime slug
     * @return {Promise<AnimeInformation | undefined>}
     */
    getAnimeInfo(slug: Slug): Promise<AnimeInformation | undefined>;
    /**
     * Get episode information
     * @param {Slug} slug Episode slug
     * @return {Promise<Episode | undefined>}
     */
    getEpisode(slug: Slug): Promise<Episode | undefined>;
    /**
     * Get batch information
     * @param {Slug} slug Batch slug
     * @return {Promise<Batch | undefined>}
     */
    getBatch(slug: Slug): Promise<Batch | undefined>;
    getSchedules(): Promise<Schedule[]>;
}

export { Odesus, types as Types, util as Util };
