type Task = () => Promise<void> | void;
type DispatchType = 'serial' | 'concurrent';
export default class CLDispatchQueue {
    private static queues: Map<string, CLDispatchQueue> = new Map();
    private static _main: CLDispatchQueue | null = null;
    private static _global: CLDispatchQueue | null = null;
    private taskQueue: Task[] = [];
    private running = false;
    private type: DispatchType;
    private label: string;
    private isCancelled = false;
    private concurrentCount: number;
    private constructor(label: string, type: DispatchType = 'serial', concurrentCount = 4) {
        this.label = label;
        this.type = type;
        this.concurrentCount = concurrentCount;
    }
    // ====== 工厂方法 ======
    static serial(label: string): CLDispatchQueue {
        if (!CLDispatchQueue.queues.has(label)) {
            CLDispatchQueue.queues.set(label, new CLDispatchQueue(label, 'serial'));
        }
        return CLDispatchQueue.queues.get(label)!;
    }
    static concurrent(label: string, concurrentCount = 4): CLDispatchQueue {
        if (!CLDispatchQueue.queues.has(label)) {
            CLDispatchQueue.queues.set(label, new CLDispatchQueue(label, 'concurrent', concurrentCount));
        }
        return CLDispatchQueue.queues.get(label)!;
    }
    // ====== 特殊队列 ======
    static get main(): CLDispatchQueue {
        if (!this._main) {
            // 模拟 UI 主线程，实际上和 serial queue 一样
            this._main = new CLDispatchQueue("main", "serial");
        }
        return this._main;
    }
    static get global(): CLDispatchQueue {
        if (!this._global) {
            // 模拟 GCD global queue，默认并发
            this._global = new CLDispatchQueue("global", "concurrent", 8);
        }
        return this._global;
    }
    // ====== 任务提交 ======
    async async(task: Task): Promise<void> {
        if (this.isCancelled)
            return;
        if (this.type === 'serial') {
            this.taskQueue.push(task);
            this.runSerial();
        }
        else {
            this.runConcurrent(task);
        }
    }
    async sync(task: Task): Promise<void> {
        if (this.isCancelled)
            return;
        await task();
    }
    private async runSerial() {
        if (this.running)
            return;
        this.running = true;
        try {
            while (this.taskQueue.length > 0 && !this.isCancelled) {
                const task = this.taskQueue.shift();
                if (task) {
                    try {
                        await task();
                    }
                    catch (e) {
                        console.error(`[Queue: ${this.label}] Task failed`, e);
                    }
                }
            }
        }
        finally {
            this.running = false;
        }
    }
    private async runConcurrent(task: Task) {
        if (this.isCancelled)
            return;
        try {
            await task();
        }
        catch (e) {
            console.error(`[Queue: ${this.label}] Concurrent task failed`, e);
        }
    }
    dispatchAfter(ms: number, task: Task) {
        setTimeout(() => {
            this.async(task);
        }, ms);
    }
    cancel() {
        this.isCancelled = true;
        this.taskQueue = [];
        console.warn(`[Queue: ${this.label}] Cancelled`);
    }
    reset() {
        this.isCancelled = false;
        console.info(`[Queue: ${this.label}] Reset`);
    }
}
