/**
 * 批量执行器模块
 * 用于管理和执行异步任务队列,支持任务去重和批量处理
 * 
 * 使用场景:
 * 1. 需要对频繁触发的操作进行批量处理
 * 2. 需要确保相同任务只执行最新一次
 * 3. 需要在下一个事件循环统一处理多个任务
 */

import { nextTick } from './Task'

/**
 * 批量执行器类
 * 
 * 核心功能:
 * - 维护异步任务队列
 * - 支持任务去重和替换
 * - 批量执行队列中的任务
 * 
 * 设计模式:
 * - 使用单例模式确保任务队列的唯一性
 * - 采用发布订阅模式处理异步任务
 * 
 * 使用示例:
 * ```typescript
 * const batch = new BatchExecution()
 * batch.push('task1', () => console.log('执行任务1'))
 * batch.push('task2', () => console.log('执行任务2'))
 * ```
 */
class BatchExecution {
  // 任务状态映射表
  private has: Record<string, boolean>
  // 任务队列
  private queue: Array<{ name: string, fn: () => void }>
  // 下一帧执行函数
  private nextTick: () => void

  constructor() {
    this.has = {}
    this.queue = []
    this.nextTick = nextTick(this.flush, this)
  }

  /**
   * 添加任务到执行队列
   * @param name - 任务唯一标识
   * @param fn - 待执行的任务函数
   * @returns void
   * 
   * 异常处理:
   * - 如果任务已存在,将替换为新任务
   * - 任务函数执行错误不会影响队列中其他任务
   */
  push(name: string, fn: () => void): void {
    if (this.has[name]) {
      this.replaceTask(name, fn)
      return
    }
    this.has[name] = true
    this.queue.push({
      name,
      fn
    })
    this.nextTick()
  }

  /**
   * 替换已存在的任务
   * @param name - 任务唯一标识
   * @param fn - 新的任务函数
   * @returns void
   */
  private replaceTask(name: string, fn: () => void): void {
    const index = this.queue.findIndex(item => {
      return item.name === name
    })
    if (index !== -1) {
      this.queue[index] = {
        name,
        fn
      }
    }
  }

  /**
   * 执行队列中的所有任务
   * 执行完成后清空队列
   * @returns void
   */
  private flush(): void {
    // 复制队列以避免执行过程中的队列变化
    let fns = this.queue.slice(0)
    this.queue = []
    fns.forEach(({ name, fn }) => {
      this.has[name] = false
      fn()
    })
  }
}

export default BatchExecution