/**
 * 消息差异计算器
 * 计算两个消息列表之间的差异，支持增量更新
 */

import {
  MessageIdentifier,
  DiffResult,
  MessageComparator,
  MessageSorter,
  DiffConfig,
  DEFAULT_DIFF_CONFIG,
} from './types';

/**
 * 消息差异计算器类
 * 用于高效计算消息列表的变化
 */
export class MessageDiffCalculator<T extends MessageIdentifier> {
  private config: Required<DiffConfig>;
  private previousMessages: Map<string, T> = new Map();
  private previousOrder: string[] = [];

  constructor(config: DiffConfig = {}) {
    this.config = { ...DEFAULT_DIFF_CONFIG, ...config };
  }

  /**
   * 计算两个消息列表的差异
   * @param oldList 旧消息列表
   * @param newList 新消息列表
   * @returns 差异结果
   */
  calculateDiff(oldList: T[], newList: T[]): DiffResult<T> {
    const result: DiffResult<T> = {
      added: [],
      updated: [],
      deleted: [],
      moved: [],
      unchanged: [],
      shouldReset: false,
    };

    // 如果旧列表为空，直接返回新列表作为新增
    if (oldList.length === 0) {
      result.added = [...newList];
      this.updateCache(newList);
      return result;
    }

    // 如果新列表为空，表示全部删除
    if (newList.length === 0) {
      result.deleted = oldList.map((msg, index) => ({ message: msg, index }));
      this.clearCache();
      return result;
    }

    // 检查是否需要重置（变化太大）
    const changeRatio = this.calculateChangeRatio(oldList, newList);
    if (changeRatio > 0.5) {
      result.shouldReset = true;
      result.added = [...newList];
      this.updateCache(newList);
      return result;
    }

    // 构建旧列表的索引映射
    const oldIndexMap = new Map<string, number>();
    oldList.forEach((msg, index) => {
      oldIndexMap.set(msg.id, index);
    });

    // 构建新列表的索引映射
    const newIndexMap = new Map<string, number>();
    newList.forEach((msg, index) => {
      newIndexMap.set(msg.id, index);
    });

    // 检测新增、更新和未变更的消息
    const processedIds = new Set<string>();

    for (let newIndex = 0; newIndex < newList.length; newIndex++) {
      const newMsg = newList[newIndex];
      const oldIndex = oldIndexMap.get(newMsg.id);

      if (oldIndex === undefined) {
        // 新增消息
        result.added.push(newMsg);
      } else {
        const oldMsg = oldList[oldIndex];
        processedIds.add(newMsg.id);

        // 检测是否有更新
        const changes = this.detectChanges(oldMsg, newMsg);
        if (changes && Object.keys(changes).length > 0) {
          result.updated.push({
            message: newMsg,
            index: oldIndex,
            changes,
          });
        } else {
          result.unchanged.push(newMsg);
        }

        // 检测是否移动
        if (oldIndex !== newIndex) {
          result.moved.push({
            message: newMsg,
            fromIndex: oldIndex,
            toIndex: newIndex,
          });
        }
      }
    }

    // 检测删除的消息
    for (let oldIndex = 0; oldIndex < oldList.length; oldIndex++) {
      const oldMsg = oldList[oldIndex];
      if (!processedIds.has(oldMsg.id)) {
        result.deleted.push({ message: oldMsg, index: oldIndex });
      }
    }

    this.updateCache(newList);
    return result;
  }

  /**
   * 计算增量差异（基于缓存的上次状态）
   * @param newList 新消息列表
   * @returns 差异结果
   */
  calculateIncrementalDiff(newList: T[]): DiffResult<T> {
    const oldList = Array.from(this.previousMessages.values());
    return this.calculateDiff(oldList, newList);
  }

  /**
   * 计算变化比例
   * @param oldList 旧列表
   * @param newList 新列表
   * @returns 变化比例（0-1）
   */
  private calculateChangeRatio(oldList: T[], newList: T[]): number {
    if (oldList.length === 0 && newList.length === 0) return 0;
    if (oldList.length === 0 || newList.length === 0) return 1;

    const oldIds = new Set(oldList.map(m => m.id));
    const newIds = new Set(newList.map(m => m.id));

    let commonCount = 0;
    oldIds.forEach(id => {
      if (newIds.has(id)) {
        commonCount++;
      }
    });

    const maxLength = Math.max(oldList.length, newList.length);
    return 1 - commonCount / maxLength;
  }

  /**
   * 检测消息变化
   * @param oldMsg 旧消息
   * @param newMsg 新消息
   * @returns 变化字段
   */
  private detectChanges(oldMsg: T, newMsg: T): Partial<T> | null {
    const changes: Partial<T> = {};
    let hasChanges = false;

    for (const key of Object.keys(newMsg) as Array<keyof T>) {
      if (key === 'id') continue; // ID 不变

      const oldValue = oldMsg[key];
      const newValue = newMsg[key];

      if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
        (changes as any)[key] = newValue;
        hasChanges = true;
      }
    }

    return hasChanges ? changes : null;
  }

  /**
   * 更新缓存
   * @param messages 消息列表
   */
  private updateCache(messages: T[]): void {
    this.previousMessages.clear();
    this.previousOrder = [];

    for (const msg of messages) {
      this.previousMessages.set(msg.id, msg);
      this.previousOrder.push(msg.id);
    }
  }

  /**
   * 清除缓存
   */
  private clearCache(): void {
    this.previousMessages.clear();
    this.previousOrder = [];
  }

  /**
   * 设置配置
   * @param config 配置
   */
  setConfig(config: Partial<DiffConfig>): void {
    this.config = { ...this.config, ...config };
  }

  /**
   * 获取当前配置
   * @returns 当前配置
   */
  getConfig(): Required<DiffConfig> {
    return { ...this.config };
  }

  /**
   * 重置计算器状态
   */
  reset(): void {
    this.clearCache();
  }

  /**
   * 获取缓存的消息数量
   * @returns 缓存数量
   */
  getCachedCount(): number {
    return this.previousMessages.size;
  }

  /**
   * 检查消息是否在缓存中
   * @param messageId 消息 ID
   * @returns 是否存在
   */
  hasMessage(messageId: string): boolean {
    return this.previousMessages.has(messageId);
  }

  /**
   * 获取缓存中的消息
   * @param messageId 消息 ID
   * @returns 消息或 undefined
   */
  getCachedMessage(messageId: string): T | undefined {
    return this.previousMessages.get(messageId);
  }
}

/**
 * 创建差异计算器实例的工厂函数
 * @param config 配置
 * @returns MessageDiffCalculator 实例
 */
export function createMessageDiffCalculator<T extends MessageIdentifier>(
  config?: DiffConfig
): MessageDiffCalculator<T> {
  return new MessageDiffCalculator<T>(config);
}
