/**
 * 差异更新 Hook
 * 接收原始消息列表，返回优化后的消息列表，自动处理批量更新
 */

import { useState, useRef, useCallback, useEffect } from 'react';
import {
  MessageIdentifier,
  MessageUpdate,
  MessageUpdateType,
  DiffConfig,
} from '../infrastructure/diff/types';
import {
  MessageDiffCalculator,
  createMessageDiffCalculator,
} from '../infrastructure/diff/MessageDiffCalculator';
import {
  MessageUpdateBatcher,
  createMessageUpdateBatcher,
  BatcherOptions,
} from '../infrastructure/diff/MessageUpdateBatcher';

/**
 * 差异更新 Hook 配置选项
 */
export interface UseDifferentialMessagesOptions<T extends MessageIdentifier> {
  /** 差异计算配置 */
  diffConfig?: DiffConfig;
  /** 批量处理配置 */
  batcherOptions?: BatcherOptions;
  /** 是否启用差异计算，默认 true */
  enableDiff?: boolean;
  /** 是否启用批量处理，默认 true */
  enableBatching?: boolean;
  /** 最大消息数量限制，超出时触发重置 */
  maxMessageCount?: number;
  /** 变化比例阈值（0-1），超过此值触发重置 */
  changeRatioThreshold?: number;
}

/**
 * 差异更新 Hook 返回值
 */
export interface UseDifferentialMessagesResult<T extends MessageIdentifier> {
  /** 优化后的消息列表 */
  optimizedMessages: T[];
  /** 待处理更新数量 */
  pendingUpdateCount: number;
  /** 是否正在处理更新 */
  isProcessing: boolean;
  /** 手动刷新方法 */
  flush: () => void;
  /** 重置方法 */
  reset: () => void;
  /** 强制刷新（跳过批量处理） */
  forceUpdate: (messages: T[]) => void;
  /** 获取差异统计信息 */
  getDiffStats: () => {
    totalBatches: number;
    totalUpdates: number;
    averageBatchSize: number;
  };
}

/**
 * 差异更新 Hook
 * @param messages 原始消息列表
 * @param options 配置选项
 * @returns 优化后的消息列表和相关方法
 */
export function useDifferentialMessages<T extends MessageIdentifier>(
  messages: T[],
  options: UseDifferentialMessagesOptions<T> = {}
): UseDifferentialMessagesResult<T> {
  const {
    diffConfig,
    batcherOptions,
    enableDiff = true,
    enableBatching = true,
    maxMessageCount = 10000,
    changeRatioThreshold = 0.5,
  } = options;

  // 状态
  const [optimizedMessages, setOptimizedMessages] = useState<T[]>(messages);
  const [isProcessing, setIsProcessing] = useState(false);
  const [pendingUpdateCount, setPendingUpdateCount] = useState(0);

  // Refs
  const calculatorRef = useRef<MessageDiffCalculator<T> | null>(null);
  const batcherRef = useRef<MessageUpdateBatcher | null>(null);
  const previousMessagesRef = useRef<T[]>([]);

  // 初始化差异计算器
  useEffect(() => {
    if (enableDiff) {
      calculatorRef.current = createMessageDiffCalculator<T>(diffConfig);
    }
    return () => {
      calculatorRef.current = null;
    };
  }, [enableDiff, diffConfig]);

  // 初始化批量处理器
  useEffect(() => {
    if (enableBatching) {
      batcherRef.current = createMessageUpdateBatcher(batcherOptions);

      // 订阅批量更新
      const unsubscribe = batcherRef.current.subscribe((updates) => {
        handleBatchUpdates(updates);
      });

      return () => {
        unsubscribe();
        batcherRef.current?.destroy();
        batcherRef.current = null;
      };
    }
  }, [enableBatching, batcherOptions]);

  // 处理批量更新
  const handleBatchUpdates = useCallback((updates: MessageUpdate[]) => {
    setIsProcessing(true);

    try {
      setOptimizedMessages((currentMessages) => {
        let newMessages = [...currentMessages];

        for (const update of updates) {
          switch (update.type) {
            case MessageUpdateType.ADD: {
              const addUpdate = update as any;
              const index = addUpdate.index ?? newMessages.length;
              newMessages.splice(index, 0, addUpdate.message);
              break;
            }

            case MessageUpdateType.BATCH_ADD: {
              const batchAddUpdate = update as any;
              const messages = batchAddUpdate.messages || [];
              const startIndex = batchAddUpdate.startIndex ?? newMessages.length;
              newMessages.splice(startIndex, 0, ...messages);
              break;
            }

            case MessageUpdateType.UPDATE: {
              const updateMsg = update as any;
              const index = newMessages.findIndex(m => m.id === updateMsg.messageId);
              if (index !== -1) {
                newMessages[index] = { ...newMessages[index], ...updateMsg.updates };
              }
              break;
            }

            case MessageUpdateType.BATCH_UPDATE: {
              const batchUpdate = update as any;
              const updates = batchUpdate.updates || [];
              for (const { messageId, changes } of updates) {
                const index = newMessages.findIndex(m => m.id === messageId);
                if (index !== -1) {
                  newMessages[index] = { ...newMessages[index], ...changes };
                }
              }
              break;
            }

            case MessageUpdateType.DELETE: {
              const deleteUpdate = update as any;
              newMessages = newMessages.filter(m => m.id !== deleteUpdate.messageId);
              break;
            }

            case MessageUpdateType.BATCH_DELETE: {
              const batchDelete = update as any;
              const idsToDelete = new Set(batchDelete.messageIds || []);
              newMessages = newMessages.filter(m => !idsToDelete.has(m.id));
              break;
            }

            case MessageUpdateType.MOVE: {
              const moveUpdate = update as any;
              const fromIndex = newMessages.findIndex(m => m.id === moveUpdate.messageId);
              if (fromIndex !== -1) {
                const [movedMessage] = newMessages.splice(fromIndex, 1);
                newMessages.splice(moveUpdate.toIndex, 0, movedMessage);
              }
              break;
            }

            case MessageUpdateType.RESET: {
              const resetUpdate = update as any;
              newMessages = resetUpdate.messages || [];
              break;
            }
          }
        }

        return newMessages;
      });
    } finally {
      setIsProcessing(false);
      setPendingUpdateCount(batcherRef.current?.getPendingCount() ?? 0);
    }
  }, []);

  // 监听外部消息变化
  useEffect(() => {
    // 如果消息数量变化太大，直接重置
    const previousCount = previousMessagesRef.current.length;
    const currentCount = messages.length;
    const changeRatio = previousCount === 0 ? 1 : Math.abs(currentCount - previousCount) / previousCount;

    if (changeRatio > changeRatioThreshold) {
      setOptimizedMessages(messages);
      previousMessagesRef.current = messages;
      return;
    }

    // 使用差异计算
    if (enableDiff && calculatorRef.current) {
      const diff = calculatorRef.current.calculateDiff(previousMessagesRef.current, messages);

      if (diff.shouldReset) {
        setOptimizedMessages(messages);
      } else {
        // 将差异转换为更新操作
        const updates: MessageUpdate[] = [];

        // 处理新增
        if (diff.added.length > 0) {
          if (diff.added.length === 1) {
            updates.push({
              type: MessageUpdateType.ADD,
              timestamp: Date.now(),
              message: diff.added[0],
            } as any);
          } else {
            updates.push({
              type: MessageUpdateType.BATCH_ADD,
              timestamp: Date.now(),
              messages: diff.added,
            } as any);
          }
        }

        // 处理更新
        if (diff.updated.length > 0) {
          if (diff.updated.length === 1) {
            updates.push({
              type: MessageUpdateType.UPDATE,
              timestamp: Date.now(),
              messageId: diff.updated[0].message.id,
              updates: diff.updated[0].changes,
            } as any);
          } else {
            updates.push({
              type: MessageUpdateType.BATCH_UPDATE,
              timestamp: Date.now(),
              updates: diff.updated.map(u => ({
                messageId: u.message.id,
                changes: u.changes,
              })),
            } as any);
          }
        }

        // 处理删除
        if (diff.deleted.length > 0) {
          if (diff.deleted.length === 1) {
            updates.push({
              type: MessageUpdateType.DELETE,
              timestamp: Date.now(),
              messageId: diff.deleted[0].message.id,
            } as any);
          } else {
            updates.push({
              type: MessageUpdateType.BATCH_DELETE,
              timestamp: Date.now(),
              messageIds: diff.deleted.map(d => d.message.id),
            } as any);
          }
        }

        // 处理移动
        if (diff.moved.length > 0) {
          for (const move of diff.moved) {
            updates.push({
              type: MessageUpdateType.MOVE,
              timestamp: Date.now(),
              messageId: move.message.id,
              toIndex: move.toIndex,
            } as any);
          }
        }

        // 应用更新
        if (updates.length > 0) {
          if (enableBatching && batcherRef.current) {
            batcherRef.current.addUpdates(updates);
          } else {
            handleBatchUpdates(updates);
          }
        }
      }
    } else {
      // 不使用差异计算，直接设置
      setOptimizedMessages(messages);
    }

    // 更新消息数量限制检查
    if (messages.length > maxMessageCount) {
      console.warn(`[useDifferentialMessages] Message count (${messages.length}) exceeds limit (${maxMessageCount})`);
    }

    previousMessagesRef.current = messages;
  }, [messages, enableDiff, enableBatching, maxMessageCount, changeRatioThreshold]);

  // 手动刷新方法
  const flush = useCallback(() => {
    batcherRef.current?.flush();
  }, []);

  // 重置方法
  const reset = useCallback(() => {
    calculatorRef.current?.reset();
    batcherRef.current?.clearPending();
    setOptimizedMessages([]);
    previousMessagesRef.current = [];
  }, []);

  // 强制更新方法
  const forceUpdate = useCallback((newMessages: T[]) => {
    setOptimizedMessages(newMessages);
  }, []);

  // 获取统计信息
  const getDiffStats = useCallback(() => {
    const batcherStats = batcherRef.current?.getStats();
    return {
      totalBatches: batcherStats?.totalBatches ?? 0,
      totalUpdates: batcherStats?.totalUpdates ?? 0,
      averageBatchSize: batcherStats?.averageBatchSize ?? 0,
    };
  }, []);

  // 定期更新待处理数量
  useEffect(() => {
    if (!enableBatching || !batcherRef.current) return;

    const interval = setInterval(() => {
      setPendingUpdateCount(batcherRef.current?.getPendingCount() ?? 0);
    }, 50);

    return () => clearInterval(interval);
  }, [enableBatching]);

  return {
    optimizedMessages,
    pendingUpdateCount,
    isProcessing,
    flush,
    reset,
    forceUpdate,
    getDiffStats,
  };
}

export default useDifferentialMessages;
