/**
 * 事件
 * 事件发送者
 * 修改 20220923
 * 支持 异步
 * 130行
 * @author 蓝面包
 * @copyright wc24@qq.com
 * @example
interface events {
    "good": [number, string, string]
}
let a = new Dispatcher<events>()
a.on("good", (a, b, c) => {
    console.log(a, b, c)
})
a.emit("good", 5, "a", "ad")
await a.emit("good", 5, "a", "ad")
 */
export default class ZeroDispatcher<T extends { [key: string]: any[] } = any> {
    private pool: {
        [key: string]: { callback: Function, target: any }[];
    };
    constructor(public target?: any) {
        this.pool = {};
    }
    /**
     * 注册事件
     * @param type
     * @param callBack 事件处理函数
     */
    on<U extends keyof T & string, K extends T[U] & any[]>(type: U, callback: (...arg: K) => void, target: any = null): void {
        let callbacks = this.pool[type];
        if (callbacks == null) {
            callbacks = [];
            this.pool[type] = callbacks;
        }
        callbacks.push({ callback: callback, target: target || this.target || this });
    }
    /**
     * 注册一次性事件事件
     * @param type
     * @param callBack 事件处理函数
     */
    once<U extends keyof T & string, K extends T[U] & any[]>(type: U, callback: (...arg: K) => void, target: any = null): void {
        let callbacks = this.pool[type];
        if (callbacks == null) {
            callbacks = [];
            this.pool[type] = callbacks;
        }
        let _callback = (...arg: K) => {
            callback(...arg)
            this.off(type, _callback)
        }
        callbacks.push({
            callback: _callback, target: target || this.target || this
        });
    }
    /**
     * 通知事件
     * @param event
     */
    emit<U extends keyof T & string, K extends T[U] & any[]>(type: U, ...arg: K): Promise<void[]> | void {
        let callbacks = this.pool[type];
        if (callbacks != null) {
            let backs: undefined | Promise<void>[]
            for (let index = 0; index < callbacks.length; index++) {
                const element = callbacks[index];
                let back = element.callback.apply(element.target, arg)
                if (back != null && Promise instanceof back) {
                    if (backs == null) {
                        backs = []
                    }
                    backs.push(back)
                }
            }
            if (backs != null) {
                return Promise.all(backs)
            }
        }
    }
    /**
     * 注销事件
     * @param type
     * @param callBack 事件处理函数
     */
    off<U extends keyof T & string, K extends T[U] & any[]>(type: U, callback: (...arg: K) => void): void {
        let callbacks = this.pool[type];
        if (callbacks != null) {
            for (let index = 0; index < callbacks.length; index++) {
                const element = callbacks[index];
                if (element.callback == callback) {
                    callbacks.splice(index, 1);
                    break
                }
            }
        }
    }
    /**
     * 是否含有事件
     * @param type
     * @param callback
     */
    has<U extends keyof T & string, K extends T[U] & any[]>(type: U, callback: (...arg: K) => void): boolean;
    has<U extends keyof T & string>(type: U): boolean;
    has<U extends keyof T & string, K extends T[U] & any[]>(type: U, callback?: (...arg: K) => void): boolean {
        if (callback == null) {
            return this.pool[type] != null;
        } else {
            let callbacks = this.pool[type];
            if (callbacks != null) {
                for (let index = 0; index < callbacks.length; index++) {
                    const element = callbacks[index];
                    if (element.callback == callback) {
                        return true
                    }
                }
                return false
            } else {
                return false
            }
        }
    }
    /**
     * 删掉所有事件
     */
    clear() {
        this.pool = {};
    }
}