/**
 * 帖子差异更新 Hook
 * 接收原始帖子列表，返回优化后的帖子列表，自动处理批量更新
 * 集成 ProcessPostUseCase 进行状态管理
 */

import { useState, useRef, useCallback, useEffect } from 'react';
import {
  PostIdentifier,
  PostUpdate,
  PostUpdateType,
  PostDiffConfig,
} from '../infrastructure/diff/postTypes';
import {
  PostDiffCalculator,
  createPostDiffCalculator,
} from '../infrastructure/diff/PostDiffCalculator';
import {
  PostUpdateBatcher,
  PostBatcherOptions,
  createPostUpdateBatcher,
} from '../infrastructure/diff/PostUpdateBatcher';
import { processPostUseCase } from '../core/usecases/ProcessPostUseCase';
import type { PostUseCaseEvent, PostsState } from '../core/usecases/ProcessPostUseCase';
import type { Post } from '../core/entities/Post';

// ==================== 类型定义 ====================

/**
 * 差异更新 Hook 配置选项
 */
export interface UseDifferentialPostsOptions<T extends PostIdentifier> {
  /** 差异计算配置 */
  diffConfig?: PostDiffConfig;
  /** 批量处理配置 */
  batcherOptions?: PostBatcherOptions;
  /** 是否启用差异计算，默认 true */
  enableDiff?: boolean;
  /** 是否启用批量处理，默认 true */
  enableBatching?: boolean;
  /** 最大帖子数量限制，超出时触发重置 */
  maxPostCount?: number;
  /** 变化比例阈值（0-1），超过此值触发重置 */
  changeRatioThreshold?: number;
  /** 列表键（用于区分不同的帖子列表） */
  listKey?: string;
  /** 是否自动订阅 UseCase 状态变化，默认 true */
  autoSubscribe?: boolean;
}

/**
 * 差异更新信息
 */
export interface DiffUpdatesInfo {
  /** 新增数量 */
  addedCount: number;
  /** 更新数量 */
  updatedCount: number;
  /** 删除数量 */
  deletedCount: number;
  /** 上次更新时间 */
  lastUpdateTime: number;
}

/**
 * 差异更新 Hook 返回值
 */
export interface UseDifferentialPostsResult<T extends PostIdentifier> {
  /** 优化后的帖子列表 */
  posts: T[];
  /** 是否正在加载 */
  loading: boolean;
  /** 是否首屏加载 */
  isInitialLoading: boolean;
  /** 是否正在加载更多 */
  isLoadingMore: boolean;
  /** 是否正在刷新 */
  refreshing: boolean;
  /** 错误信息 */
  error: string | null;
  /** 是否有更多数据 */
  hasMore: boolean;
  /** 待处理更新数量 */
  pendingUpdateCount: number;
  /** 是否正在处理更新 */
  isProcessing: boolean;
  /** 刷新方法 */
  refresh: () => Promise<void>;
  /** 加载更多方法 */
  loadMore: () => Promise<void>;
  /** 手动刷新批量处理队列 */
  flush: () => void;
  /** 重置方法 */
  reset: () => void;
  /** 强制更新（跳过批量处理） */
  forceUpdate: (posts: T[]) => void;
  /** 获取差异统计信息 */
  getDiffStats: () => {
    totalBatches: number;
    totalUpdates: number;
    averageBatchSize: number;
  };
  /** 差异更新信息 */
  diffUpdates: DiffUpdatesInfo;
}

// ==================== Hook 实现 ====================

/**
 * 帖子差异更新 Hook
 * @param initialPosts 初始帖子列表（可选）
 * @param options 配置选项
 * @returns 优化后的帖子列表和相关方法
 */
export function useDifferentialPosts<T extends PostIdentifier = Post>(
  initialPosts: T[] = [],
  options: UseDifferentialPostsOptions<T> = {}
): UseDifferentialPostsResult<T> {
  const {
    diffConfig,
    batcherOptions,
    enableDiff = true,
    enableBatching = true,
    maxPostCount = 10000,
    listKey = 'default',
    autoSubscribe = true,
  } = options;

  // ==================== 状态 ====================

  const [posts, setPosts] = useState<T[]>(initialPosts);
  const [loading, setLoading] = useState(false);
  const [refreshing, setRefreshing] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [hasMore, setHasMore] = useState(true);
  const [isProcessing, setIsProcessing] = useState(false);
  const [pendingUpdateCount, setPendingUpdateCount] = useState(0);
  const [diffUpdates, setDiffUpdates] = useState<DiffUpdatesInfo>({
    addedCount: 0,
    updatedCount: 0,
    deletedCount: 0,
    lastUpdateTime: 0,
  });

  // ==================== Refs ====================

  const calculatorRef = useRef<PostDiffCalculator<T> | null>(null);
  const batcherRef = useRef<PostUpdateBatcher | null>(null);
  const previousPostsRef = useRef<T[]>(initialPosts);
  const unsubscribeRef = useRef<(() => void) | null>(null);

  // ==================== 批量更新处理（须在订阅 batcher 的 useEffect 之前定义）====================

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

    try {
      setPosts((currentPosts) => {
        let newPosts = [...currentPosts];
        let addedCount = 0;
        let updatedCount = 0;
        let deletedCount = 0;

        for (const update of updates) {
          switch (update.type) {
            case PostUpdateType.ADD: {
              const addUpdate = update as any;
              const index = addUpdate.index ?? newPosts.length;
              newPosts.splice(index, 0, addUpdate.post as T);
              addedCount++;
              break;
            }

            case PostUpdateType.BATCH_ADD: {
              const batchAddUpdate = update as any;
              const postsToAdd = batchAddUpdate.posts || [];
              const startIndex = batchAddUpdate.startIndex ?? newPosts.length;
              newPosts.splice(startIndex, 0, ...postsToAdd as T[]);
              addedCount += postsToAdd.length;
              break;
            }

            case PostUpdateType.UPDATE: {
              const updatePost = update as any;
              const index = newPosts.findIndex(p => p.id === updatePost.postId);
              if (index !== -1) {
                newPosts[index] = { ...newPosts[index], ...updatePost.updates };
                updatedCount++;
              }
              break;
            }

            case PostUpdateType.BATCH_UPDATE: {
              const batchUpdate = update as any;
              const updatesList = batchUpdate.updates || [];
              for (const { postId, changes } of updatesList) {
                const index = newPosts.findIndex(p => p.id === postId);
                if (index !== -1) {
                  newPosts[index] = { ...newPosts[index], ...changes };
                  updatedCount++;
                }
              }
              break;
            }

            case PostUpdateType.DELETE: {
              const deleteUpdate = update as any;
              const prevLength = newPosts.length;
              newPosts = newPosts.filter(p => p.id !== deleteUpdate.postId);
              if (newPosts.length < prevLength) {
                deletedCount++;
              }
              break;
            }

            case PostUpdateType.BATCH_DELETE: {
              const batchDelete = update as any;
              const idsToDelete = new Set(batchDelete.postIds || []);
              const prevLength = newPosts.length;
              newPosts = newPosts.filter(p => !idsToDelete.has(p.id));
              deletedCount += prevLength - newPosts.length;
              break;
            }

            case PostUpdateType.MOVE: {
              const moveUpdate = update as any;
              const fromIndex = newPosts.findIndex(p => p.id === moveUpdate.postId);
              if (fromIndex !== -1) {
                const [movedPost] = newPosts.splice(fromIndex, 1);
                newPosts.splice(moveUpdate.toIndex, 0, movedPost);
              }
              break;
            }

            case PostUpdateType.RESET: {
              const resetUpdate = update as any;
              newPosts = resetUpdate.posts || [];
              break;
            }
          }
        }

        // 更新差异统计
        if (addedCount > 0 || updatedCount > 0 || deletedCount > 0) {
          setDiffUpdates(prev => ({
            addedCount: prev.addedCount + addedCount,
            updatedCount: prev.updatedCount + updatedCount,
            deletedCount: prev.deletedCount + deletedCount,
            lastUpdateTime: Date.now(),
          }));
        }

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

  // ==================== 初始化 ====================

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

  // 初始化批量处理器
  useEffect(() => {
    if (!enableBatching) return;

    batcherRef.current = createPostUpdateBatcher(batcherOptions);

    const unsubscribe = batcherRef.current.subscribe((updates) => {
      handleBatchUpdates(updates);
    });

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

  // ==================== UseCase 订阅 ====================

  /**
   * 处理 UseCase 事件
   */
  const handleUseCaseEvent = useCallback((event: PostUseCaseEvent) => {
    switch (event.type) {
      case 'state_changed': {
        const { key: eventKey, state } = event.payload as { key: string; state: PostsState };
        // 全局订阅：只应用当前列表 key，避免其他 Tab/列表的 state 覆盖本列表（如 createPost 会更新所有 key）
        if (eventKey !== listKey) {
          break;
        }
        if (state) {
          setLoading(state.isLoading);
          setRefreshing(state.isRefreshing);
          setError(state.error);
          setHasMore(state.hasMore);

          // ProcessPostUseCase 的 state.posts 已是合并后的完整列表。
          // 不再走差异计算 + PostUpdateBatcher：批量应用晚于 previousPostsRef 更新时，
          // BATCH_ADD 会在过短的 currentPosts 上 splice，导致连续游标加载「请求成功但列表不增长」。
          batcherRef.current?.clearPending();
          calculatorRef.current?.reset();
          if (state.posts && state.posts.length > 0) {
            const next = state.posts as unknown as T[];
            if (next.length > maxPostCount) {
              console.warn(`[useDifferentialPosts] Post count (${next.length}) exceeds limit (${maxPostCount})`);
            }
            setPosts(next);
            previousPostsRef.current = next;
          } else {
            setPosts([]);
            previousPostsRef.current = [];
          }
        }
        break;
      }

      case 'posts_loaded': {
        // fetchPosts 在 updatePostsState 时已发出 state_changed（含合并后 posts），此处不再应用，避免与其它 key 竞态或重复计算
        break;
      }

      case 'post_created': {
        const { post } = event.payload;
        if (post) {
          // 新帖子添加到列表开头
          setPosts(prev => [post as T, ...prev]);
          setDiffUpdates(prev => ({
            ...prev,
            addedCount: prev.addedCount + 1,
            lastUpdateTime: Date.now(),
          }));
        }
        break;
      }

      case 'post_updated': {
        const { post } = event.payload;
        if (post) {
          setPosts(prev => prev.map(p => p.id === post.id ? { ...p, ...post } as T : p));
          setDiffUpdates(prev => ({
            ...prev,
            updatedCount: prev.updatedCount + 1,
            lastUpdateTime: Date.now(),
          }));
        }
        break;
      }

      case 'post_deleted': {
        const { postId } = event.payload;
        if (postId) {
          setPosts(prev => prev.filter(p => p.id !== postId));
          setDiffUpdates(prev => ({
            ...prev,
            deletedCount: prev.deletedCount + 1,
            lastUpdateTime: Date.now(),
          }));
        }
        break;
      }

      case 'loading_changed': {
        const { isLoading } = event.payload;
        setLoading(isLoading);
        break;
      }

      case 'error_occurred': {
        const payload = event.payload as { key?: string; error?: string };
        if (payload.key !== undefined && payload.key !== listKey) {
          break;
        }
        if (payload.error !== undefined) {
          setError(payload.error);
        }
        break;
      }
    }
  }, [listKey, maxPostCount]);

  // 订阅 UseCase 状态变化
  useEffect(() => {
    if (autoSubscribe) {
      unsubscribeRef.current = processPostUseCase.subscribe(handleUseCaseEvent);

      // 初始化时获取当前状态
      const currentState = processPostUseCase.getPostsState(listKey);
      if (currentState.posts.length > 0) {
        setPosts(currentState.posts as unknown as T[]);
        previousPostsRef.current = currentState.posts as unknown as T[];
      }
      setLoading(currentState.isLoading);
      setRefreshing(currentState.isRefreshing);
      setError(currentState.error);
      setHasMore(currentState.hasMore);

      return () => {
        if (unsubscribeRef.current) {
          unsubscribeRef.current();
          unsubscribeRef.current = null;
        }
      };
    }
  }, [autoSubscribe, listKey, handleUseCaseEvent]);

  // ==================== 操作方法 ====================

  /**
   * 刷新帖子列表
   */
  const refresh = useCallback(async () => {
    setRefreshing(true);
    setError(null);
    try {
      await processPostUseCase.refreshPosts(listKey);
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : '刷新失败';
      setError(errorMsg);
    } finally {
      setRefreshing(false);
    }
  }, [listKey]);

  /**
   * 加载更多帖子
   */
  const loadMore = useCallback(async () => {
    if (hasMore && !loading) {
      setLoading(true);
      setError(null);
      try {
        await processPostUseCase.loadMorePosts(listKey);
      } catch (err) {
        const errorMsg = err instanceof Error ? err.message : '加载更多失败';
        setError(errorMsg);
      } finally {
        setLoading(false);
      }
    }
  }, [listKey, hasMore, loading]);

  /**
   * 手动刷新批量处理队列
   */
  const flush = useCallback(() => {
    batcherRef.current?.flush();
  }, []);

  /**
   * 重置方法
   */
  const reset = useCallback(() => {
    calculatorRef.current?.reset();
    batcherRef.current?.clearPending();
    setPosts([]);
    setLoading(false);
    setRefreshing(false);
    setError(null);
    setHasMore(true);
    previousPostsRef.current = [];
    setDiffUpdates({
      addedCount: 0,
      updatedCount: 0,
      deletedCount: 0,
      lastUpdateTime: 0,
    });
  }, []);

  /**
   * 强制更新方法
   */
  const forceUpdate = useCallback((newPosts: T[]) => {
    setPosts(newPosts);
    previousPostsRef.current = newPosts;
  }, []);

  /**
   * 获取统计信息
   */
  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 {
    posts,
    loading,
    isInitialLoading: loading && posts.length === 0 && !refreshing,
    isLoadingMore: loading && posts.length > 0 && !refreshing,
    refreshing,
    error,
    hasMore,
    pendingUpdateCount,
    isProcessing,
    refresh,
    loadMore,
    flush,
    reset,
    forceUpdate,
    getDiffStats,
    diffUpdates,
  };
}

export default useDifferentialPosts;
