/**
 * 消息更新批量处理器
 * 收集更新操作并按批处理，减少 UI 更新次数
 */

import {
  MessageUpdate,
  MessageUpdateType,
  BaseMessageUpdate,
  BatchUpdateListener,
  DiffConfig,
  DEFAULT_DIFF_CONFIG,
  MessageIdentifier,
} from './types';

/**
 * 批量处理器配置选项
 */
export interface BatcherOptions {
  /** 批量处理间隔（毫秒），默认 16ms（约 60fps） */
  batchInterval?: number;
  /** 最大批量大小，默认 100 */
  maxBatchSize?: number;
  /** 是否启用去重，默认 true */
  enableDeduplication?: boolean;
  /** 是否合并相同消息的多次更新，默认 true */
  enableMerge?: boolean;
  /** 最大等待时间（毫秒），超过此时间强制刷新，默认 100ms */
  maxWaitTime?: number;
  /** 是否自动启动批量处理，默认 true */
  autoStart?: boolean;
}

/**
 * 默认批量处理器配置
 */
export const DEFAULT_BATCHER_OPTIONS: Required<BatcherOptions> = {
  batchInterval: 16,
  maxBatchSize: 100,
  enableDeduplication: true,
  enableMerge: true,
  maxWaitTime: 100,
  autoStart: true,
};

/**
 * 消息更新批量处理器类
 */
export class MessageUpdateBatcher {
  /** 待处理的更新队列 */
  private pendingUpdates: Map<string, MessageUpdate> = new Map();
  /** 批量处理定时器 */
  private batchTimer: ReturnType<typeof setTimeout> | null = null;
  /** 最大等待时间定时器 */
  private maxWaitTimer: ReturnType<typeof setTimeout> | null = null;
  /** 监听器集合 */
  private listeners: Set<BatchUpdateListener> = new Set();
  /** 是否正在批处理中 */
  private isProcessing: boolean = false;
  /** 配置选项 */
  private options: Required<BatcherOptions>;
  /** 处理器是否已启动 */
  private isStarted: boolean = false;
  /** 批量处理统计信息 */
  private stats: {
    totalBatches: number;
    totalUpdates: number;
    averageBatchSize: number;
    lastBatchTime: number;
  } = {
    totalBatches: 0,
    totalUpdates: 0,
    averageBatchSize: 0,
    lastBatchTime: 0,
  };

  constructor(options: BatcherOptions = {}) {
    this.options = { ...DEFAULT_BATCHER_OPTIONS, ...options };
    if (this.options.autoStart) {
      this.start();
    }
  }

  /**
   * 启动批量处理器
   */
  start(): void {
    if (this.isStarted) return;
    this.isStarted = true;
    this.scheduleBatch();
  }

  /**
   * 停止批量处理器
   */
  stop(): void {
    this.isStarted = false;
    this.clearTimers();
  }

  /**
   * 添加更新操作到批量队列
   * @param update 消息更新操作
   */
  addUpdate(update: MessageUpdate): void {
    const key = this.generateUpdateKey(update);

    // 去重：如果已有相同消息 ID 的待处理更新，进行合并
    if (this.options.enableDeduplication && this.pendingUpdates.has(key)) {
      const existing = this.pendingUpdates.get(key)!;

      if (this.options.enableMerge) {
        const merged = this.mergeUpdates(existing, update);
        if (merged) {
          this.pendingUpdates.set(key, merged);
          return;
        }
      }
    }

    this.pendingUpdates.set(key, update);

    // 如果达到最大批量大小，立即刷新
    if (this.pendingUpdates.size >= this.options.maxBatchSize) {
      this.flush();
    }
  }

  /**
   * 添加多个更新操作
   * @param updates 更新操作数组
   */
  addUpdates(updates: MessageUpdate[]): void {
    for (const update of updates) {
      this.addUpdate(update);
    }
  }

  /**
   * 立即刷新所有待处理更新
   * @returns 处理的更新数组
   */
  flush(): MessageUpdate[] {
    if (this.pendingUpdates.size === 0 || this.isProcessing) {
      return [];
    }

    this.isProcessing = true;
    this.clearTimers();

    const updates = Array.from(this.pendingUpdates.values());
    this.pendingUpdates.clear();

    // 更新统计信息
    this.stats.totalBatches++;
    this.stats.totalUpdates += updates.length;
    this.stats.averageBatchSize = this.stats.totalUpdates / this.stats.totalBatches;
    this.stats.lastBatchTime = Date.now();

    // 通知监听器
    this.notifyListeners(updates);

    this.isProcessing = false;

    // 重新调度定时器
    this.scheduleBatch();

    return updates;
  }

  /**
   * 订阅批量更新事件
   * @param listener 监听器函数
   * @returns 取消订阅函数
   */
  subscribe(listener: BatchUpdateListener): () => void {
    this.listeners.add(listener);
    return () => {
      this.listeners.delete(listener);
    };
  }

  /**
   * 取消订阅
   * @param listener 监听器函数
   */
  unsubscribe(listener: BatchUpdateListener): void {
    this.listeners.delete(listener);
  }

  /**
   * 获取待处理更新数量
   * @returns 待处理数量
   */
  getPendingCount(): number {
    return this.pendingUpdates.size;
  }

  /**
   * 获取统计信息
   * @returns 统计信息
   */
  getStats() {
    return { ...this.stats };
  }

  /**
   * 检查是否有待处理更新
   * @returns 是否有待处理更新
   */
  hasPendingUpdates(): boolean {
    return this.pendingUpdates.size > 0;
  }

  /**
   * 清空所有待处理更新
   */
  clearPending(): void {
    this.pendingUpdates.clear();
    this.clearTimers();
  }

  /**
   * 销毁批量处理器
   */
  destroy(): void {
    this.stop();
    this.clearPending();
    this.listeners.clear();
  }

  /**
   * 生成更新键值
   * @param update 更新操作
   * @returns 键值
   */
  private generateUpdateKey(update: MessageUpdate): string {
    // 根据更新类型生成唯一键
    switch (update.type) {
      case 'ADD':
      case 'BATCH_ADD':
        return `${update.type}_${update.timestamp}`;
      case 'UPDATE':
      case 'BATCH_UPDATE':
        return `${update.type}_${this.extractMessageId(update)}`;
      case 'DELETE':
      case 'BATCH_DELETE':
        return `${update.type}_${this.extractMessageId(update)}`;
      default:
        return `${update.type}_${update.timestamp}_${Math.random()}`;
    }
  }

  /**
   * 提取消息 ID
   * @param update 更新操作
   * @returns 消息 ID 或空字符串
   */
  private extractMessageId(update: MessageUpdate): string {
    const payload = (update as any).payload;
    if (payload) {
      if (payload.messageId) return payload.messageId;
      if (payload.messageIds) return payload.messageIds.join(',');
    }
    return '';
  }

  /**
   * 合并更新操作
   * @param existing 已有更新
   * @param incoming 新更新
   * @returns 合并后的更新或 null（如果无法合并）
   */
  private mergeUpdates(existing: MessageUpdate, incoming: MessageUpdate): MessageUpdate | null {
    // 只有同类型的更新才能合并
    if (existing.type !== incoming.type) {
      return null;
    }

    switch (existing.type) {
      case 'UPDATE':
        // 合并更新字段
        return {
          ...existing,
          payload: {
            ...(existing as any).payload,
            updates: {
              ...(existing as any).payload?.updates,
              ...(incoming as any).payload?.updates,
            },
          },
          timestamp: incoming.timestamp,
        };

      case 'BATCH_UPDATE':
        // 合并批量更新
        const existingUpdates = (existing as any).payload?.updates || [];
        const incomingUpdates = (incoming as any).payload?.updates || [];
        const updatesMap = new Map();

        for (const update of [...existingUpdates, ...incomingUpdates]) {
          const existing = updatesMap.get(update.messageId);
          if (existing) {
            existing.changes = { ...existing.changes, ...update.changes };
          } else {
            updatesMap.set(update.messageId, { ...update });
          }
        }

        return {
          ...existing,
          payload: {
            ...(existing as any).payload,
            updates: Array.from(updatesMap.values()),
          },
          timestamp: incoming.timestamp,
        };

      default:
        return null;
    }
  }

  /**
   * 调度批量处理
   */
  private scheduleBatch(): void {
    if (!this.isStarted) return;

    this.clearTimers();

    // 设置最大等待时间定时器
    this.maxWaitTimer = setTimeout(() => {
      this.flush();
    }, this.options.maxWaitTime);

    // 设置批量处理定时器
    this.batchTimer = setTimeout(() => {
      this.flush();
    }, this.options.batchInterval);
  }

  /**
   * 清除所有定时器
   */
  private clearTimers(): void {
    if (this.batchTimer) {
      clearTimeout(this.batchTimer);
      this.batchTimer = null;
    }
    if (this.maxWaitTimer) {
      clearTimeout(this.maxWaitTimer);
      this.maxWaitTimer = null;
    }
  }

  /**
   * 通知监听器
   * @param updates 更新数组
   */
  private notifyListeners(updates: MessageUpdate[]): void {
    if (this.listeners.size === 0) return;

    // 转换为数组以支持迭代
    const listenersArray = Array.from(this.listeners);
    for (const listener of listenersArray) {
      try {
        listener(updates);
      } catch (error) {
        console.error('Error in batch update listener:', error);
      }
    }
  }
}

/**
 * 创建批量处理器的工厂函数
 * @param options 配置选项
 * @returns MessageUpdateBatcher 实例
 */
export function createMessageUpdateBatcher(
  options?: BatcherOptions
): MessageUpdateBatcher {
  return new MessageUpdateBatcher(options);
}
