type DownloadUrl = string | URL;
type DownloadRequest = {
    url: DownloadUrl;
} & RequestInit;
type DownloadInput = DownloadUrl | DownloadRequest | Request | Promise<Response>;
type DownloadFetchCallback = () => Promise<Response>;

declare class DownloadTaskError extends Error {
    readonly task: DownloadTask;
    constructor(msg: string, task: DownloadTask);
}
declare enum DownloadTaskState {
    error = -1,
    init = 0,
    fetching = 1,
    reading = 2,
    complete = 3
}
type DownloadTaskProcessCallback = (task: DownloadTask) => void | Promise<void>;
type DownloadTaskProcessOptions = {
    onFetch?: DownloadTaskProcessCallback;
    onHeaders?: DownloadTaskProcessCallback;
    onProgress?: DownloadTaskProcessCallback;
    onComplete?: DownloadTaskProcessCallback;
    onError?: DownloadTaskProcessCallback;
};
declare class DownloadTask {
    #private;
    /**
     * 创建 {@link DownloadTask} 实例，允许多种 input 类型
     *
     * ```ts
     * // URL 输入
     * const task1 = new DownloadTask('url');
     * const task2 = new DownloadTask(new URL('url'));
     *
     * // Request or DownloadRequest 结构
     * const task3 = new DownloadTask(new Request('url'));
     * const task4 = new DownloadTask({ url: 'url' });
     *
     * // Promise<Response>
     * const abort = new AbortController();
     * const task5 = new DownloadTask(fetch('url', { signal: abort.signal }));
     *
     * // Response
     * const task6 = new DownloadTask(await fetch('url'));
     * ```
     *
     * 下载的目标 url ，必须要输出有效的 `content-length`，否则将会抛出异常
     *
     * @param input
     */
    constructor(input: DownloadInput | Response);
    protected _initFetch: (input: DownloadInput) => void;
    /**
     * {@link DownloadTask} Id
     *
     * 用于给 {@link DownloadTask} 的 Key 使用
     */
    get id(): string;
    /**
     * 获取 response
     */
    get resp(): Response | undefined;
    /**
     * 当前状态 {@link DownloadTaskState}
     */
    get state(): DownloadTaskState;
    /**
     * 获取 Response Content-Length
     */
    get contentLength(): number;
    /**
     * 获取 Response Content-Encoding
     */
    get encoding(): string | null;
    /**
     * 获取 Response Content-Type
     */
    get mimeType(): string | null;
    /**
     * 实际接收内容的大小
     */
    get size(): number;
    /**
     * Response 是否经过压缩（基于 Content-Encoding 判定）
     */
    get isCompressed(): boolean;
    /**
     * 强制指定 compressed ，针对一些特殊的场合使用
     *
     * @param isCompressed
     */
    setCompressed: (isCompressed?: boolean) => this;
    /**
     * 已接收 Response body 大小
     */
    get received(): number;
    /**
     * 接收 Response body 进度小数（0 - 1）
     */
    get progress(): number;
    /**
     * 接收 Response body 进度百分比（0 - 100）
     */
    get percent(): number;
    /**
     * 获取 Response body 的 chunks
     */
    get chunks(): Uint8Array<ArrayBufferLike> | undefined;
    /**
     * 是否开始 read
     */
    get isStarted(): boolean;
    /**
     * 是否已经读取（完毕） Response body
     */
    get isReaded(): boolean;
    /**
     * 获取错误信息
     */
    get error(): unknown;
    /**
     * read 完成时间戳
     *
     * - 如果下载未开始，返回 0
     * - 如果下载已开始，但并未下载完成，则会返回当前时间的时间戳
     */
    get completeTs(): number;
    /**
     * read 数据经过多少时间（毫秒）
     *
     * 如果为实际完成，则返回当前时间的时间戳
     *
     * 如果未开始，则返回 0
     */
    get elapsedMs(): number;
    /**
     * 接收速度，单位为字节/秒，需要自行转换
     *
     * 如果未开始，返回 0
     *
     * ```ts
     * import { filesize } from 'filesize';
     *
     * const task = await fetchDownload().read();
     *
     * console.log(`${filesize(task.speed, { bits: true })}/s`); // kbit/s
     * console.log(`${filesize(task.speed)}/s`); // KB/s
     * ```
     */
    get speed(): number;
    /**
     * read response body（下载）
     *
     * 主要的流程：
     *
     * 1. 如果创建 {@link DownloadTask} 实例时输入的非 Response 实例 {@link DownloadInput}
     * 会创建一个函数去 fetch 输入（主要是 fetch headers，如果传入的是 Response 实例，则跳过这一步）。
     *     - `onFetch` 对应 fetch 前
     * 2. 解析 `Response.headers`，并提取 `content-length`、`content-type`、`content-encoding`，
     * 其中 `content-length` 为必须的（缺失或小于或等于0时将抛出错误）。
     *     - `onHeaders`
     * 3. `stream.read` 实际开始下载
     *     - `onProgress` 每一次接收 chunk 流
     *     - `onComplete` 下载完成
     *     - `onError` 出错时
     *
     * 默认状态下，任意错误都会抛出异常，可通过 `opts.isNotThrow` 为 `true` 禁用抛出异常。
     *
     * ```ts
     * const task = new DownloadTask('download_url');
     * await task.read({
     *   onFetch: () => {},    // fetch 前
     *   onHeaders: () => {},  // 读取 headers 时，stream read 之前
     *   onProgress: () => {}, // 每一次接收 chunk 流时
     *   onComplete: () => {}, // 下载完成时
     *   onError: () => {},    // 出错时
     * });
     * ```
     *
     * @param opts
     */
    read: (opts?: DownloadTaskProcessCallback | DownloadTaskProcessOptions) => Promise<this>;
    /**
     * 根据压缩后文件大小，推算出未压缩前的文件大小
     *
     * 文本内容的压缩率，实际取决于源内容的重复率，所以无法一概而论。
     * 这里只是尽可能放大压缩后的尺寸，以取得一个较为接近的值
     *
     * @param compressedSize 压缩后的文件大小
     */
    inferUncompressedSize: (compressedSize: number) => number;
    newErr: (msg: string) => DownloadTaskError;
}

declare class DownloadQueueError extends Error {
    readonly queue: DownloadQueue;
    constructor(msg: string, queue: DownloadQueue);
}
type DownloadQueueInput = DownloadInput | Response | DownloadTask;
type DownloadQueueProcessCallback = (queue: DownloadQueue, task: DownloadTask) => void | Promise<void>;
type DownloadQueueProcessOptions = {
    onFetch?: DownloadQueueProcessCallback;
    onHeaders?: DownloadQueueProcessCallback;
    onProgress?: DownloadQueueProcessCallback;
    onComplete?: DownloadQueueProcessCallback;
    onError?: DownloadQueueProcessCallback;
    onFinish?: (queue: DownloadQueue) => void | Promise<void>;
    onQueueError?: (queue: DownloadQueue) => void | Promise<void>;
};
declare class DownloadQueue {
    #private;
    /**
     * 创建 {@link DownloadQueue} 实例，允许多种 input 类型
     *
     * ```ts
     * // DownloadTask
     * const task1 = new DownloadQueue([new DownloadTask('url')]);
     * const task2 = new DownloadQueue([fetchDownload('url')]);
     *
     * // URL 输入
     * const task3 = new DownloadQueue(['url']);
     * const task4 = new DownloadQueue([new URL('url')]);
     *
     * // Request or DownloadRequest 结构
     * const task5 = new DownloadQueue([new Request('url')]);
     * const task6 = new DownloadQueue([{ url: 'url' }]);
     *
     * // Promise<Response>
     * const abort = new AbortController();
     * const task7 = new DownloadQueue([
     *   fetch('url', { signal: abort.signal }),
     * ]);
     *
     * // Response
     * const task8 = new DownloadTask([
     *   await fetch('url'),
     * ]);
     * ```
     *
     * @param tasks
     */
    constructor(tasks: DownloadQueueInput[]);
    /**
     * {@link DownloadQueue} Id
     */
    get id(): string;
    /**
     * 所有下载任务
     */
    get tasks(): DownloadTask[];
    /**
     * 所有下载任务的总数
     */
    get tasksCount(): number;
    /**
     * 当前状态 {@link DownloadTaskState}
     *
     * 注意 {@link DownloadQueue} 不应该出现 `fetching` 状态
     */
    get state(): DownloadTaskState;
    /**
     * 所有下载任务的实际总大小
     */
    get size(): number;
    /**
     * 所有下载任务的 Content-Length 总和
     */
    get contentLength(): number;
    /**
     * 所有下载任务的已接收 Response body 大小
     */
    get received(): number;
    /**
     * 所有下载任务的接收 Response body 进度小数（0 - 1）
     */
    get progress(): number;
    /**
     * 所有下载任务的接收 Response body 进度百分比（0 - 100）
     */
    get percent(): number;
    /**
     * 是否开始 read
     */
    get isStarted(): boolean;
    /**
     * 是否已经 read 完毕
     */
    get isReaded(): boolean;
    /**
     * 获取错误信息
     */
    get error(): unknown;
    /**
     * read 完成时间戳（所有下载任务都完成）
     *
     * - 如果下载未开始，返回 0
     * - 如果下载已开始，但并未下载完成，则会返回当前时间的时间戳
     */
    get completeTs(): number;
    /**
     * read 数据经过多少时间（毫秒，所有下载任务都完成）
     *
     * 如果为实际完成，则返回当前时间的时间戳
     *
     * 如果未开始，则返回 0
     */
    get elapsedMs(): number;
    /**
     * 接收速度（所有下载任务的平均值），单位为字节/秒，需要自行转换
     *
     * 如果未开始，返回 0
     *
     * ```ts
     * import { filesize } from 'filesize';
     *
     * const task = await fetchDownload().read();
     *
     * console.log(`${filesize(task.speed, { bits: true })}/s`); // kbit/s
     * console.log(`${filesize(task.speed)}/s`); // KB/s
     * ```
     */
    get speed(): number;
    protected _initTasksQueue: (opts?: DownloadQueueProcessOptions) => Promise<DownloadTask>[];
    reduce: <T>(fn: (acc: T, it: DownloadTask) => T, initValue: T) => T;
    /**
     * Queue 读取方法（调用每一个 task 的 read）
     *
     * 1. `onFetch`、`onHeaders`、`onProgress`、`onComplete`、`onError` 保留对应每一个 task 的事件
     * 2. `onFinish` 对应 Queue 全部 tasks 读取完毕
     * 3. `onQueueError` 对应 Queue 任意一个 task 读取过程中出错
     *
     * @param opts
     */
    read: (opts?: DownloadQueueProcessCallback | DownloadQueueProcessOptions) => Promise<this>;
    newErr: (msg: string) => DownloadQueueError;
}

/**
 * 创建 {@link DownloadTask} 或 {@link DownloadQueue} 的快捷方法
 *
 * ```ts
 * // DownloadTask
 * const task = fetchDownload('url');
 *
 * // DownloadQueue
 * const queue = fetchDownload(['url-a', 'url-b', 'url-c']);
 * ```
 *
 * @param input
 */
declare const fetchDownload: <T extends DownloadInput | DownloadInput[], R = T extends DownloadInput ? DownloadTask : DownloadQueue>(input: T) => R;

/**
 * 将 chunks 保存到本机，该方法只可在浏览器中执行
 *
 * ```ts
 * const task = fetchDownload('url');
 * await task.read();
 *
 * saveChunks(task.chunks, 'test.js');
 * ```
 *
 * @param chunks
 * @param filename
 * @param mimeType
 */
declare const saveChunks: (chunks: Uint8Array, filename: string | (() => string), mimeType?: string | null) => void;

export { DownloadQueue, DownloadQueueError, DownloadTask, DownloadTaskError, DownloadTaskState, fetchDownload, saveChunks };
export type { DownloadFetchCallback, DownloadInput, DownloadQueueInput, DownloadQueueProcessCallback, DownloadQueueProcessOptions, DownloadRequest, DownloadTaskProcessCallback, DownloadTaskProcessOptions, DownloadUrl };
