import { Framework } from "../Framework";

export type NextFunction = (nextArgs?: any) => void;
export type AsyncCallback = (next: NextFunction, params: any, args: any) => void;

interface AsyncTask {
    /**
     * 任务uuid
     */
    uuid: number;
    /**
     * 任务开始执行的回调
     * params: push时传入的参数
     * args: 上个任务传来的参数
     */
    callbacks: Array<AsyncCallback>;
    /**
     * 任务参数
     */
    params: any
}

export class AsyncQueue {
    private _runningAsyncTask: AsyncTask = null;            //正在运行的任务
    private static _$uuid_count: number = 1;                //任务task的唯一标识
    private _queues: Array<AsyncTask> = [];                 //任务队列
    complete: Function | null = null;                       //任务队列完成回调

    get queues(): Array<AsyncTask> {
        return this._queues;
    }

    private _isProcessingTaskUUID: number = 0;              //正在执行的异步任务标识
    private _enable: boolean = true;                        //是否启动
    /**
     * 是否开启可用
     */
    get enable() {
        return this._enable;
    }
    /**
     * 是否开启可用
     */
    set enable(val: boolean) {
        if (this._enable !== val) {
            this._enable = val;
            if (val && this.size > 0) {
                this.play();
            }
        }
    }

    /**
     * push一个异步任务到队列中
     * 返回任务uuid
     */
    push(callback: AsyncCallback, params: any = null) {
        let uuid = ++AsyncQueue._$uuid_count;
        this._queues.push({
            uuid: uuid,
            callbacks: [callback],
            params: params
        })
        return uuid;
    }

    /**
     * push多个任务,多个任务函数会同时执行,
     * 返回任务uuid
     */
    pushMulti(params: any, ...callbacks: AsyncCallback[]) {
        let uuid = ++AsyncQueue._$uuid_count;
        this._queues.push({
            uuid: uuid,
            callbacks: callbacks,
            params: params
        })
        return uuid;
    }

    /** 移除一个还未执行的异步任务 */
    remove(uuid: number) {
        if (this._runningAsyncTask?.uuid === uuid) {
            console.error("正在执行的任务不可以移除");
            return;
        }
        for (let i = 0; i < this._queues.length; ++i) {
            if (this._queues[i].uuid === uuid) {
                this._queues.splice(i, 1);
                break;
            }
        }
    }

    /**
     * 队列长度
     */
    get size(): number {
        return this._queues.length;
    }

    /**
     * 是否有正在处理的任务
     */
    get isProcessing(): boolean {
        return this._isProcessingTaskUUID > 0;
    }

    /**
     * 队列是否已停止
     */
    get isStop(): boolean {
        return (this._queues.length > 0 || this.isProcessing) ? false : true;
    }

    /** 正在执行的任务参数 */
    get runningParams() {
        return this._runningAsyncTask ? this._runningAsyncTask.params : null;
    }

    /**
     * 清空队列
     */
    clear() {
        this._queues = [];
        this._isProcessingTaskUUID = 0;
        this._runningAsyncTask = null;
    }

    protected _next_task(taskUUID: number, args: any = null) {
        if (this._isProcessingTaskUUID === taskUUID) {
            this._isProcessingTaskUUID = 0;
            this._runningAsyncTask = null;
            this.play(args);
        } else {
            if (this._runningAsyncTask) {
                console.log(this._runningAsyncTask);
            }
        }
    }

    /**
     * 跳过当前正在执行的任务
     */
    step() {
        (this.isProcessing) && this._next_task(this._isProcessingTaskUUID);
    }

    /**
     * 开始运行队列
     */
    play(args: any = null) {
        if (this.isProcessing || !this._enable) {
            return;
        }
        let actionData: AsyncTask = this._queues.shift()!;
        if (actionData) {
            this._runningAsyncTask = actionData;
            let taskUUID: number = actionData.uuid;
            this._isProcessingTaskUUID = taskUUID;
            let callbacks: Array<AsyncCallback> = actionData.callbacks;

            if (callbacks.length == 1) {
                let nextFunc: NextFunction = (nextArgs: any = null) => {
                    this._next_task(taskUUID, nextArgs);
                }
                callbacks[0](nextFunc, actionData.params, args);
            } else {
                // 多个任务函数同时执行
                let fnum: number = callbacks.length;
                let nextArgsArr: any[] = [];
                let nextFunc: NextFunction = (nextArgs: any = null) => {
                    --fnum;
                    nextArgsArr.push(nextArgs || null);
                    if (fnum === 0) {
                        this._next_task(taskUUID, nextArgsArr);
                    }
                }
                let knum = fnum;
                for (let i = 0; i < knum; ++i) {
                    callbacks[i](nextFunc, actionData.params, args);
                }
            }
        } else {
            this._isProcessingTaskUUID = 0;
            this._runningAsyncTask = null;
            (this.complete) && this.complete(args);
        }
    }

    /**
     * 往队列中push一个延时任务
     * @param time 时间(秒)
     * @param callback 时间到了之后回调
     */
    yieldTime(time: number, callback: Function = null) {
        let task = function (next: Function, params: any, args: any) {
            Framework.time.scheduleOnce(() => {
                callback && callback();
                next(args);
            }, time);
        }
        this.push(task, { des: "AsyncQueue.yieldTime" });
    }

    /**
     * 返回一个执行函数,执行函数调用count次后,next将触发
     * @param count 
     * @param next 
     * @return 返回一个匿名函数
     */
    static excuteTimes(count: number, next: Function = null) {
        let fnum: number = count;
        let tempCall = () => {
            --fnum;
            if (fnum === 0) {
                next && next();
            }
        }
        return tempCall;
    }
}

/**
 * let queue: AsyncQueue = new AsyncQueue();
 * //添加一个异步任务
 * queue.push(async (next: NextFunction, params: any, args: any) => {
 *      load("",type,(error,res)=>{
 *          next && next();
 *      });
 * });
 * 
 * //任务完成后的回调函数
 * queue.complete = () => {
 * 
 * }
 * 
 * //执行异步任务
 * queue.play();
 */