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

import {
  PostUpdate,
  PostUpdateType,
  PostBatchUpdateListener,
  PostDiffConfig,
  DEFAULT_POST_DIFF_CONFIG,
  PostIdentifier,
  PostUpdateBatch,
} from './postTypes';

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

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

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

  constructor(options: PostBatcherOptions = {}) {
    this.options = { ...DEFAULT_POST_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: PostUpdate): 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: PostUpdate[]): void {
    for (const update of updates) {
      this.addUpdate(update);
    }
  }

  /**
   * 立即刷新所有待处理更新
   * @returns 处理的更新数组
   */
  flush(): PostUpdate[] {
    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;
  }

  /**
   * 刷新并返回批次对象
   * @returns 批次对象或 null
   */
  flushAsBatch(): PostUpdateBatch | null {
    const updates = this.flush();
    if (updates.length === 0) return null;

    return {
      batchId: `batch_${++this.batchIdCounter}_${Date.now()}`,
      updates,
      createdAt: Date.now(),
      processed: false,
    };
  }

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

  /**
   * 取消订阅
   * @param listener 监听器函数
   */
  unsubscribe(listener: PostBatchUpdateListener): 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: PostUpdate): string {
    // 根据更新类型生成唯一键
    const updateType = (update as PostUpdate).type;
    switch (updateType) {
      case PostUpdateType.ADD:
      case PostUpdateType.BATCH_ADD:
        return `${updateType}_${(update as any).timestamp}`;
      case PostUpdateType.UPDATE:
      case PostUpdateType.BATCH_UPDATE:
        return `${updateType}_${this.extractPostId(update)}`;
      case PostUpdateType.DELETE:
      case PostUpdateType.BATCH_DELETE:
        return `${updateType}_${this.extractPostId(update)}`;
      case PostUpdateType.MOVE:
        return `${updateType}_${(update as any).postId}`;
      case PostUpdateType.RESET:
        return `${updateType}_${(update as any).timestamp}`;
      default:
        // 兜底处理未知类型
        return `unknown_${Date.now()}_${Math.random()}`;
    }
  }

  /**
   * 提取帖子 ID
   * @param update 更新操作
   * @returns 帖子 ID 或空字符串
   */
  private extractPostId(update: PostUpdate): string {
    const payload = (update as any).payload;
    if (payload) {
      if (payload.postId) return payload.postId;
      if (payload.postIds) return payload.postIds.join(',');
    }
    // 直接从更新对象提取
    if ((update as any).postId) return (update as any).postId;
    if ((update as any).postIds) return (update as any).postIds.join(',');
    return '';
  }

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

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

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

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

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

      case PostUpdateType.BATCH_DELETE:
        // 合并删除 ID 列表
        const existingIds = new Set((existing as any).payload?.postIds || []);
        const incomingIds = (incoming as any).payload?.postIds || [];
        for (const id of incomingIds) {
          existingIds.add(id);
        }
        return {
          ...existing,
          payload: {
            ...(existing as any).payload,
            postIds: Array.from(existingIds),
          },
          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: PostUpdate[]): 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 post batch update listener:', error);
      }
    }
  }

  // ==================== 便捷方法 ====================

  /**
   * 添加帖子新增操作
   */
  addPost(post: PostIdentifier, index?: number): void {
    this.addUpdate({
      type: PostUpdateType.ADD,
      post,
      index,
      timestamp: Date.now(),
    });
  }

  /**
   * 添加帖子更新操作
   */
  updatePost(postId: string, updates: Partial<PostIdentifier>): void {
    this.addUpdate({
      type: PostUpdateType.UPDATE,
      postId,
      updates,
      timestamp: Date.now(),
    });
  }

  /**
   * 添加帖子删除操作
   */
  deletePost(postId: string): void {
    this.addUpdate({
      type: PostUpdateType.DELETE,
      postId,
      timestamp: Date.now(),
    });
  }

  /**
   * 批量添加帖子
   */
  batchAddPosts(posts: PostIdentifier[], startIndex?: number): void {
    this.addUpdate({
      type: PostUpdateType.BATCH_ADD,
      posts,
      startIndex,
      timestamp: Date.now(),
    });
  }

  /**
   * 批量更新帖子
   */
  batchUpdatePosts(updates: Array<{ postId: string; changes: Partial<PostIdentifier> }>): void {
    this.addUpdate({
      type: PostUpdateType.BATCH_UPDATE,
      updates,
      timestamp: Date.now(),
    });
  }

  /**
   * 批量删除帖子
   */
  batchDeletePosts(postIds: string[]): void {
    this.addUpdate({
      type: PostUpdateType.BATCH_DELETE,
      postIds,
      timestamp: Date.now(),
    });
  }

  /**
   * 重置帖子列表
   */
  resetPosts(posts: PostIdentifier[]): void {
    this.addUpdate({
      type: PostUpdateType.RESET,
      posts,
      timestamp: Date.now(),
    });
  }
}

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