/**
 * worker 工具
 *
 * @remarks
 * worker-tls 提供了关于worker 的一些工具，用于便捷地使用 worker
 *
 * @packageDocumentation
 */

import type { AnyFunction } from 'type-tls';
import dynamicWorkerCodeString from '/temp/dynamicWorkerMain.iife.js?raw';
import listenMessages_Dep from '/temp/listenMessages_Dep.iife.js?raw';
import type { Optional } from 'type-tls';
import type { PickMethod } from 'type-tls';

/**
 * 转为异步的命令
 * @remarks
 * 函数的入参不变，返回参数都变为解决值为对应类型的 Promise
 * 其它非函数的值都变为返回解决值为对应类型的 Promise 的函数
 */
export declare type AsyncCMD<Value> = Value extends AnyFunction ? AsyncFun<Value> : (() => Promise<Awaited<Value>>);

/**
 * 把函数转为异步函数
 */
export declare type AsyncFun<Fun extends (...args: any) => any> = GetExecFunResultData<Fun> extends ReadableStream ? (...args: AsyncFunArgs<Fun>) => GetExecFunResultData<Fun> : (...args: AsyncFunArgs<Fun>) => Promise<GetExecFunResultData<Fun>>;

/**
 * 异步函数的参数类型
 */
export declare type AsyncFunArgs<Fun extends (...args: any) => any> = Parameters<Fun> | [CallOptions<Parameters<Fun>>];

/**
 * 函数的调用选项
 *
 * @remarks
 * 用于设置 transfer
 */
export declare interface CallOptions<Args extends any[] = any[]> {
    /**
     * 给worker 里对应的函数传递的参数
     */
    args: Args;
    /**
     * 设置将参数传送给 worker 时可转移的数据
     */
    transfer: Transferable[];
}

/**
 * 代码片段
 */
export declare type CodePart = Fun | BlobPart;

/**
 * 代码块列表
 */
export declare type CodePartList = (CodePart | INamedFunction | INamedFunctionMap)[];

/**
 * 代码块选项的综合定义
 */
export declare type CodePartOptions = CodePartList | INamedFunctionMap;

/**
 * 打包 options 中的代码并转成 BlobPart[]
 * @remarks
 * 传入的所有的代码块最终会被分为以下几类：
 *
 * 1. `code` 和 `named` 中的所有具有名字的 函数和数据都会被挂载在 Worker 中的 `globalThis` 上，其中 名字会作为 属性名字；
 *
 * 2. `code` 和 `named`中的 匿名函数 以及 `iife` 中的函数 会被作为 立即调用函数在 Worker 启动时作为顶层代码被立即执行；
 *
 * 3. `message` 监听器会在 Worker 中接收 `message` 事件；
 *
 * @param options
 * @param noDep - 禁止包含 创建 Worker 时所需要的其它依赖代码（环境代码）
 * @returns
 */
export declare function createBlobParts(options: IWorkerCodes, noDep?: Optional<boolean>): BlobPart[];

/**
 * 创建动态 Worker
 *
 * @param worker - worker实例
 * @param name - worker中运行的js文件的url
 * @param url - Worker 中所包含的初始代码
 * @param code - Worker 中所包含的初始代码
 * @param workerOptions - Worker 相关的选项
 * @returns
 */
export declare function createDynamicWorker<Members, W extends AbstractWorker = Worker>(noCode?: undefined | null, workerOptions?: Optional<DynamicWorkerOptions<W>>): MembersToAsyncCMD<Members> & DynamicWorker<W>;

export declare function createDynamicWorker<Members, W extends AbstractWorker = Worker>(worker: W, name?: string): MembersToAsyncCMD<Members> & DynamicWorker<W>;

export declare function createDynamicWorker<Members, W extends AbstractWorker = Worker>(url: string, workerOptions?: Optional<Omit<DynamicWorkerOptions<W>, "noDep">>): MembersToAsyncCMD<Members> & DynamicWorker<W>;

export declare function createDynamicWorker<Members extends Record<string | number, any>, W extends AbstractWorker = Worker>(code: DynamicWorkerCodes<PickMethod<Members>>, workerOptions?: Optional<DynamicWorkerOptions<W>>): MembersToAsyncCMD<Members> & DynamicWorker<W>;

export declare function createDynamicWorker<Members extends Record<string | number, any>, W extends AbstractWorker = Worker>(codeOptions?: Optional<DynamicWorkerCodes<Members> | string | W>, workerOptions?: Optional<DynamicWorkerOptions<W> | string>): MembersToAsyncCMD<Members> & DynamicWorker<W>;

/**
 * 创建动态 Worker 池
 *
 * @param workerNum - Worker池 中 workder 的个数
 * @param codeOptions - Worker 中所包含的初始代码
 * @param workerOptions - Worker 相关的选项
 * @returns
 */
export declare function createDynamicWorkerPool<Members extends Record<string | number, any>, W extends AbstractWorker = Worker>(workerNum: number, codeOptions?: Optional<IWorkerCodes | string>, workerOptions?: Optional<DynamicWorkerOptions<W>>): MembersToAsyncCMD<Members> & DynamicWorkerPool<W>;

/**
 * 生成可用于创建动态 Worker 的 url
 *
 * @remarks
 *
 * {@inheritDoc ./stringify.ts#dynamicWorkerCodeString}
 *
 * @param codeOptions - 往 Worker 中注入代码的配置选项
 * @param noDep - 禁止包含 创建 Worker 时所需要的其它依赖代码（环境代码）
 */
export declare function createDynamicWorkerURL(codeOptions?: Optional<IWorkerCodes>, noDep?: Optional<boolean>): string;

/**
 * 通过代码构建 ObjectURL
 * @param codes
 * @param args - 对于立即调用的函数传的参数
 * @returns
 */
export declare function createObjectURLByCodes(codes: CodePart[], args?: Optional<any[]>): string;

/**
 * 将一组脚本内容构造成 ObjectURL
 * @param scripts - 脚本内容
 * @param options - 选项
 * @returns url字符串
 */
export declare function createObjectURLByContents(scripts: BlobPart[], options?: BlobPropertyBag | null): string;

/**
 * 创建Worker客户端的代理
 * @param client
 * @returns
 */
export declare function createWorkerClientProxy<WClient extends WorkerClient<AbstractWorker>>(client: WClient): any;

/**
 * 生成可用于创建 worker 的 url
 * @remarks
 * 打包 codeOptions 中的代码并生成可用于创建 worker 的 url
 * @param codeOptions - 往 Worker 中注入代码的配置选项
 * @param noDep - 禁止包含 创建 Worker 时所需要的其它依赖代码（环境代码）
 * @returns
 */
export declare function createWorkerURL(codeOptions: IWorkerCodes, noDep?: Optional<boolean>): string;

/**
 * 动态 Worker 给 Worker 扩展后的类型
 */
export declare type DWorker<W extends AbstractWorker> = W & {
    /**
     * 当前正在执行的任务数
     */
    executingCount: number;
    /**
     * Worker的名字
     */
    name: string;
    /**
     * Worker所属的 WorkerClient 的id
     */
    clientId: number;
    /**
     * Worker 本身的 id
     */
    id: number;
};

/**
 * 动态Worker
 *
 * @remarks
 * 动态 Worker 具备以下特点：
 *
 * - 往 Worker 中添加函数、全局变量 等
 *
 * - 调用 Worker 中的任意全局函数 或 全局变量
 *
 * - 像调用本地方法一样调用 Worker 里的方法
 *
 * - 会自动给实例自身添加快捷命令
 *
 * - 支持异步、流
 *
 * - 支持异步和流互相嵌套
 */
export declare class DynamicWorker<W extends AbstractWorker = Worker> extends WorkerClient<W> {
    /**
     *
     * @param worker 已创建好的 worker 实例
     * @param name
     */
    constructor();
    constructor(worker: W, name?: string);
    constructor(url: string, workerOptions?: Optional<Omit<DynamicWorkerOptions<W>, "noDep">>);
    constructor(code: IWorkerCodes, workerOptions?: Optional<DynamicWorkerOptions<W>>);
    constructor(codeOrUrlOrWorker?: Optional<IWorkerCodes | string | W>, workerOptionsOrName?: Optional<DynamicWorkerOptions<W> | string>);
    /**
     * Worker 的实例
     */
    worker: DWorker<W>;
    /**
     * 正在执行中的任务数
     */
    get executingCount(): number;
    /**
     * 设置命令
     * @remarks
     * 会在Worker中添加一条命令，并且也会在实例自身上添加一个快捷命令（快捷方法 或 快捷属性）
     *
     * @param cmd
     * @param name - 命令的命名；默认会取 `cmd.name` 作为名字；当 cmd 是字符串时，name 是必须的
     * @param isProperty - 添加到实例自身的快捷命令是否作为属性；如果是 true，则会在实例自身上生成快捷属性
     * @returns
     */
    setCMD(cmd: string | AnyFunction, name?: Optional<string>, isProperty?: Optional<boolean>): Promise<boolean>;
    /**
     * 移除命令
     * @remarks
     * 会将 Worker 中的命令 和 自己实例上的对应快捷方法都给移除
     * @param name
     * @returns
     */
    removeCMD(name: string): Promise<boolean>;
}

/**
 * 动态 Worker 的初始配置 code
 */
export declare type DynamicWorkerCodes<Methods extends INamedFunctionMap> = Omit<IWorkerCodes, "named"> & {
    named?: Optional<Methods | INamedFunctionList>;
};

export { dynamicWorkerCodeString }

/**
 * 从 worker 实例创建 动态 Worker 的选项
 */
export declare interface DynamicWorkerFromInstOptions<W extends AbstractWorker = Worker> {
    /**
     * Worker 实例
     */
    worker: W;
    /**
     * worker 的名字
     */
    name?: string;
}

/**
 * 动态 Worker 的选项
 */
export declare interface DynamicWorkerOptions<W extends AbstractWorker = Worker> {
    /**
     * 获取 Worker 实例的方法
     * @defaultValue 默认会创建私有 Worker
     */
    getWorker?: Optional<GetWorker<W>>;
    /**
     * worker 的名字
     */
    name?: string;
    /**
     * 是否是不自动添加 动态 worker 依赖的环境代码
     * 如果明确指定为 true，则不会包含 动态 worker 依赖的环境代码
     * @defaultValue true
     */
    noDep?: boolean;
}

/**
 * 动态Worker池
 */
export declare class DynamicWorkerPool<W extends AbstractWorker = Worker> extends WorkerClient<W> {
    /**
     *
     * @param workerNum - Worker池 中 workder 的个数
     * @param codeOrUrl - code 选项 或 url
     * @param workerOptions - Worker 相关的选项
     */
    constructor(workerNum: number, codeOrUrl?: Optional<IWorkerCodes | string>, workerOptions?: Optional<DynamicWorkerOptions<W>>);
    /**
     * Worker 队列
     */
    readonly queue: SortQueue<DWorker<W>>;
    get worker(): DWorker<W>;
    get executingCount(): number;
    execStarted(worker: DWorker<W>, execRec: ExecRecord): void;
    execEnded(worker: DWorker<W>): void;
    /**
     * 在指定 worker 中的执行命令
     *
     * @remarks
     * 当 worker 中成功执行，且 this 上没有对应的成员时，则会自动新增对应的成员方法
     *
     * @param exec - 命令信息
     * @param transfer - 传递给 Worker 的可传递对象。这些对象的所有权将被转移给 Worker，而发当前环境将不再保有所有权。
     * @returns
     */
    execCMDOnWorker(worker: DWorker<W>, exec: Exec, transfer?: Transferable[]): Promise<any>;
    /**
     * 在所有 worker 中的执行命令
     *
     * @remarks
     * 当 worker 中成功执行，且 this 上没有对应的成员时，则会自动新增对应的成员方法
     *
     * @param exec - 命令信息
     * @param transfer - 传递给 Worker 的可传递对象。这些对象的所有权将被转移给 Worker，而发当前环境将不再保有所有权。
     * @returns
     */
    allExecCMD(exec: Exec, transfer?: Transferable[]): Promise<any[]>;
    /**
     * 设置命令
     * @remarks
     * 会在Worker中添加一条命令，并且也会在实例自身上添加一个快捷命令（快捷方法 或 快捷属性）
     *
     * @param cmd
     * @param name - 命令的命名；默认会取 `cmd.name` 作为名字；当 cmd 是字符串时，name 是必须的
     * @param isProperty - 添加到实例自身的快捷命令是否作为属性；如果是 true，则会在实例自身上生成快捷属性
     * @returns
     */
    setCMD(cmd: string | AnyFunction, name?: Optional<string>, isProperty?: Optional<boolean>): Promise<boolean[]>;
    /**
     * 移除命令
     * @remarks
     * 会将 Worker 中的命令 和 自己实例上的对应快捷方法都给移除
     * @param name
     * @returns
     */
    removeCMD(name: string): Promise<boolean[]>;
}

/**
 * 命令执行信息
 * @remarks
 * 命令有两种类型：
 *
 * + 函数：
 *
 *  - 执行命令就是执行函数
 *
 *  - 执行命令的返回值就是函数的返回值
 *
 * + 数据：
 *
 *  - 执行命令就是访问这个数据对象
 *
 *  - 执行命令的返回值就这个数据本身
 */
declare interface Exec {
    /**
     * 被执行对象的名字
     */
    name: string;
    /**
     * 函数式命令的参数
     * @remarks
     * 如果传递了该选项，则命令一定会被当作函数来处理
     */
    args?: Optional<any[]>;
    /**
     * 函数式命令的 this 值
     * @remarks
     * 如果传递了该选项，则命令一定会被当作函数来处理
     */
    this?: any;
}

/**
 * 命令执行的记录
 */
declare interface ExecRecord extends Exec {
    /**
     * 本次执行的id
     */
    id: string;
}

/**
 * 函数 或 函数代码
 */
declare type Fun = AnyFunction | FunctionCode;

/**
 * 定义函数的代码
 *
 * @remarks
 * 可从 `fun.toString()` 得到
 */
declare type FunctionCode = string;

/**
 * 提取 函数 Fun 的返回类型 ExecRes<D> 中的 D 的类型
 */
export declare type GetExecFunResultData<Fun extends (...args: any) => any> = GetExecResultData<Awaited<ReturnType<Fun>>>;

/**
 * 提取 ExecRes<D> 中的 D 的类型
 * @remarks
 * 用于提取 ExecResult 类型中的 D 的类型
 */
export declare type GetExecResultData<ExecRes> = ExecRes extends {
    data: infer D;
} ? D : ExecRes;

/**
 * 获取 Worker 的回调函数
 * @remarks
 * 这个函数就是用来根据回调的入参创建 worker 实例的
 *
 * @param url - 用于创建 Worker 的 url；
 * @param name - Worker 的名字
 */
export declare type GetWorker<W extends AbstractWorker = Worker> = (info: WorkerInfo) => W;

/**
 * 默认的 getWorker
 * @param url
 * @param name
 * @returns
 */
export declare function getWorker_Default(info: WorkerInfo): Worker;

/**
 * 定义命名的函数
 *
 */
export declare interface INamedFunction {
    /**
     * 保存函数的变量名
     */
    name?: Optional<string>;
    /**
     * 函数
     */
    fun: AnyFunction;
}

/**
 * 命名函数的数组
 */
export declare type INamedFunctionList = (AnyFunction | INamedFunction | INamedFunctionMap)[];

/**
 * 定义命名的函数
 *
 * @remarks
 * 属性名字作为保存函数的变量名，即：函数名
 */
export declare interface INamedFunctionMap {
    [name: string | number]: AnyFunction;
}

/**
 * 命名函数选项的综合定义
 */
export declare type INamedFunctions = INamedFunctionList | INamedFunctionMap;

/**
 * CallOptions 的类型保卫
 * @param target
 * @returns
 */
export declare function isCallOptions(target: any): target is CallOptions;

/**
 * worker 的代码选项
 */
export declare interface IWorkerCodes {
    /**
     * 代码块
     * @remarks
     * - `code` 和 `named` 中的所有具有名字的 函数和数据都会被挂载在 `Worker` 中的 `globalThis` 上，其中 名字会作为 属性名字；
     *
     * - `code` 和 `named`中的 匿名函数 以及 `iife` 中的函数 会被作为 立即调用函数在 `Worker` 启动时作为顶层代码被立即执行；
     */
    code?: Optional<CodePartOptions>;
    /**
     * 命名的函数
     *
     * @remarks
     * 这些函数会被保存在 `Worker` 中的对应名字的全局变量中。
     *
     * - `code` 和 `named` 中的所有具有名字的 函数和数据都会被挂载在 `Worker` 中的 `globalThis` 上，其中 名字会作为 属性名字；
     *
     * - `code` 和 `named`中的 匿名函数 以及 `iife` 中的函数 会被作为 立即调用函数在 `Worker` 启动时作为顶层代码被立即执行；
     */
    named?: Optional<INamedFunctions>;
    /**
     * 在 Wokrer 中会被立即执行的函数
     * @remarks
     * 这些函数会被作为 立即调用函数在 Worker 启动时作为顶层代码被立即执行；
     */
    iife?: Optional<AnyFunction[]>;
    /**
     * 会作为 message 事件监听器的函数。
     * @remarks
     * 这些函数会在 Worker 中接收 `message` 事件；
     *
     * **注意：** 并不是所有的 监听器 都会被直接添加到 `message` 事件上；只有以 函数名字（即：`JSIdentifier` 类型的监听器） 指定的 事件会被直接添加到 `message` 事件上，其它类型的监听器都是以函数调用并传递 `message` 事件参数的形式来响应 `message` 事件，
     */
    message?: Optional<(AnyFunction | JSIdentifier | Partial<INamedFunction>)[]>;
}

/**
 * js 的标识符
 *
 * @remarks
 *
 * 比如变量名
 */
declare type JSIdentifier = string;

export { listenMessages_Dep }

/**
 * 将所有成员都 转为 异步h命令
 *
 * @remarks
 * 所有的方法的入参不变，返回参数都变为解决值为对应类型的 Promise
 * 所有的属性都变为返回解决值为对应类型的 Promise 的方法
 */
export declare type MembersToAsyncCMD<Target> = {
    [N in keyof Target]: AsyncCMD<Target[N]>;
};

export declare type SortComparer<Item> = (a: Item, b: Item) => number;

/**
 * 排序队列
 * @remarks
 * 优先队列的极简实现；即优化了排序的性能，又保持代码精简；
 */
export declare class SortQueue<Item = any> {
    comparer: SortComparer<Item>;
    constructor(comparer: SortComparer<Item>, items?: Item[]);
    /**
     * 队列
     * @remarks
     * 保存所有的元素
     */
    get queue(): Item[];
    set queue(value: Item[]);
    protected _queue: Item[];
    /**
     * 第一个元素
     */
    get first(): Item;
    /**
     * 最后一个元素
     */
    get last(): NonNullable<Item>;
    /**
     * 添加元素
     * @param items
     * @returns 返回item最终的索引
     */
    add(item: Item): number;
    /**
     * 添加元素
     * @param items
     */
    addItems(items: Iterable<Item>): void;
    /**
     * 删除元素
     * @param items
     * @returns 返回item删除前所在的索引
     */
    delete(item: Item): number;
    /**
     * 删除元素
     * @param items
     */
    deleteItems(items: Iterable<Item>): void;
    /**
     * 对队列中的所有元素重新排序
     */
    sort(): void;
    /**
     * 排序 item
     * @param item
     * @returns 如果item 不在队列中，返回 false；否则返回 true
     */
    sortItem(item: Item): number;
    /**
     * 前向排序
     * @param item
     * @returns 返回item最终的索引
     */
    forwardSort(item: Item): number;
    /**
     * 后向排序
     * @param item
     * @returns 返回item最终的索引
     */
    backwardSort(item: Item): number;
    /**
     * 排序 item
     * @param index
     * @returns 返回item最终的索引
     */
    sortItemForIndex(index: number): number;
    /**
     * 前向排序
     * @param index
     * @returns 返回item最终的索引
     */
    forwardSortForIndex(index: number): number;
    /**
     * 后向排序
     * @param index
     * @returns 返回item最终的索引
     */
    backwardSortForIndex(index: number): number;
}

/**
 * 将所有方法都 转为 异步方法
 *
 * @remarks
 * 所有的方法的入参不变，返回参数都变为解决值为对应类型的 Promise
 *
 * @typeParam Methods - 包含方法的对象
 */
export declare type ToAsyncMethods<Methods extends INamedFunctionMap> = {
    [N in keyof Methods]: AsyncFun<Methods[N]>;
};

/**
 * 动态Worker 抽像基类
 *
 * @remarks
 * 动态 Worker 具备以下特点：
 *
 * - 往 Worker 中添加函数、全局变量 等
 *
 * - 调用 Worker 中的任意全局函数 或 全局变量
 *
 * - 像调用本地方法一样调用 Worker 里的方法
 *
 * - 会自动给实例自身添加快捷命令
 *
 * - 支持异步、流
 *
 * - 支持异步和流互相嵌套
 *
 * - 支持  Worker 和 SharedWorker
 */
export declare abstract class WorkerClient<W extends AbstractWorker = Worker> {
    constructor(named?: Optional<INamedFunctions>);
    /**
     * 实例的计数
     *
     * @remarks
     * 用于给每次调用生成 id
     */
    protected static instanceCount: number;
    readonly id: number;
    /**
     * Worker 的实例
     */
    abstract worker: DWorker<W>;
    /**
     * 消息端口
     */
    get port(): MessagePort;
    /**
     * 获取 Worker 和 对应的 消息端口
     */
    get workerAndPort(): [DWorker<W>, MessagePort];
    /**
     * 获取消息端口
     * @param worker
     * @returns
     */
    getPort(worker: W): MessagePort;
    /**
     * 正在执行中的任务数
     */
    abstract executingCount: number;
    /**
     * 执行已开始
     * @remarks
     * 开始执行
     */
    execStarted(worker: DWorker<W>, execRec: ExecRecord): void;
    /**
     * 执行已开始
     * @remarks
     * 开始执行
     */
    execEnded(worker: DWorker<W>): void;
    /**
     * 执行命令的计数
     *
     * @remarks
     * 用于给每次执行命令时生成 id
     */
    protected execCount: number;
    /**
     * 获取本次执行的执行 id
     * @param cmdName
     * @returns
     */
    getExecId(cmdName?: Optional<string>): string;
    /**
     * 根据调用信息生成调用记录数据
     * @param exec - 调用信息
     * @returns
     */
    getExecRecord(exec: Exec): ExecRecord;
    /**
     * 监听响应
     * @param id
     * @returns
     */
    listenResponse(id: string, worker: DWorker<W>): Promise<any>;
    /**
     * 执行 worker 中的命令
     *
     * @remarks
     * 当 worker 中成功执行，且 this 上没有对应的成员时，则会自动新增对应的成员方法
     *
     * @param exec - 命令信息
     * @param transfer - 传递给 Worker 的可传递对象。这些对象的所有权将被转移给 Worker，而发当前环境将不再保有所有权。
     * @returns
     */
    execCMD(exec: Exec, transfer?: Transferable[]): Promise<any>;
    /**
     * 往自身上添加命令成员
     * @remarks
     * 会给实例自身上添加一个执行命令的快捷命令
     *
     * @param name
     * @param isProperty - 添加到实例自身的快捷命令是否作为属性；如果是 true，则会在实例自身上生成快捷属性
     */
    setCMDToSelf(name: string, isProperty?: Optional<boolean>): boolean;
}

/**
 * worker 的信息
 */
export declare interface WorkerInfo {
    /**
     * worker 要加载的代码的url
     */
    url: string;
    /**
     * worker 的名字
     */
    name: string;
    /**
     * worker 客户端 的 id
     */
    clientId: number;
    /**
     * worker 的 id
     */
    id: number;
}

/**
 * worker 优先级比较器
 * @remarks
 * 按照 executingCount 的从小到大排列
 * @param a
 * @param b
 */
export declare function workerPriorityComparator<W extends AbstractWorker>(a: DWorker<W>, b: DWorker<W>): number;

export { }
