import { useState, useCallback, useRef, useEffect } from 'react';
import {
  CursorPaginationState,
  CursorPaginationConfig,
  CursorDirection,
  UseCursorPaginationReturn,
  CursorFetchFunction,
} from '../infrastructure/pagination/types';
import { CursorPaginationResponse } from '../types/dto';

const DEFAULT_PAGE_SIZE = 20;
const MAX_PAGE_SIZE = 100;

function getItemId(item: unknown): string | null {
  if (!item || typeof item !== 'object') return null;
  const maybeId = (item as { id?: unknown }).id;
  if (typeof maybeId === 'string' || typeof maybeId === 'number') {
    return String(maybeId);
  }
  return null;
}

function mergeByIdFastPath<T>(previousInput: T[] | null | undefined, incomingInput: T[] | null | undefined): T[] {
  const previous = Array.isArray(previousInput) ? previousInput : [];
  const incoming = Array.isArray(incomingInput) ? incomingInput : [];
  if (incoming.length === 0) return previous;
  if (previous.length === 0) return incoming;

  const prevLastId = getItemId(previous[previous.length - 1]);
  const incomingFirstId = getItemId(incoming[0]);
  if (prevLastId && incomingFirstId && prevLastId !== incomingFirstId) {
    const prevSet = new Set(previous.map((item) => getItemId(item)).filter(Boolean) as string[]);
    if (!prevSet.has(incomingFirstId)) {
      return [...previous, ...incoming];
    }
  }

  const merged = [...previous];
  const indexById = new Map<string, number>();
  for (let i = 0; i < merged.length; i += 1) {
    const id = getItemId(merged[i]);
    if (id) indexById.set(id, i);
  }

  for (const item of incoming) {
    const id = getItemId(item);
    if (!id) {
      merged.push(item);
      continue;
    }
    const existingIndex = indexById.get(id);
    if (existingIndex === undefined) {
      indexById.set(id, merged.length);
      merged.push(item);
    } else {
      merged[existingIndex] = item;
    }
  }
  return merged;
}

function normalizeList<T>(value: T[] | null | undefined): T[] {
  return Array.isArray(value) ? value : [];
}

/**
 * 游标分页 Hook
 *
 * @param fetchFunction 数据获取函数
 * @param config 分页配置
 * @param extraParams 额外参数（会传递给 fetchFunction）
 */
export function useCursorPagination<T, P = void>(
  fetchFunction: CursorFetchFunction<T, P>,
  config: Partial<CursorPaginationConfig> = {},
  extraParams?: P
): UseCursorPaginationReturn<T> {
  const { pageSize = DEFAULT_PAGE_SIZE, bidirectional = false, autoLoad = true } = config;
  
  // 限制 pageSize 在有效范围内
  const effectivePageSize = Math.min(Math.max(1, pageSize), MAX_PAGE_SIZE);
  
  const [state, setState] = useState<CursorPaginationState<T>>({
    list: [],
    nextCursor: null,
    prevCursor: null,
    hasMore: true, // 初始设为 true，以便首次加载可以执行
    isLoading: false,
    isInitialLoading: false,
    isLoadingMore: false,
    isRefreshing: false,
    error: null,
    isFirstLoad: true,
  });
  
  // 用于取消请求的标志
  const cancelledRef = useRef(false);
  
  // 用于追踪是否已自动加载
  const autoLoadRef = useRef(false);
  
  // 用于追踪是否为首次加载的 ref
  const isFirstLoadRef = useRef(true);
  
  // 用于追踪是否正在加载中（防止重复调用）
  const isLoadingRef = useRef(false);
  
  // 加载更多（下一页）
  const loadMore = useCallback(async () => {
    // 使用 ref 来检查是否为首次加载，避免依赖项变化
    const isFirstLoad = isFirstLoadRef.current;
    
    // 首次加载时允许执行（跳过 hasMore 检查）
    // 使用 isLoadingRef 防止重复调用
    if (isLoadingRef.current || state.isLoading || (!isFirstLoad && !state.hasMore)) {
      return;
    }
    
    // 标记正在加载
    isLoadingRef.current = true;
    cancelledRef.current = false;
    
    setState(prev => ({
      ...prev,
      isLoading: true,
      isInitialLoading: prev.list.length === 0,
      isLoadingMore: prev.list.length > 0,
      error: null,
    }));
    
    try {
      const response: CursorPaginationResponse<T> = await fetchFunction({
        cursor: state.nextCursor || undefined,
        direction: 'forward',
        pageSize: effectivePageSize,
        extraParams,
      });
      
      if (cancelledRef.current) {
        isLoadingRef.current = false;
        return;
      }
      
      // 标记首次加载完成
      isFirstLoadRef.current = false;
      
      const incomingList = normalizeList(response.list);
      setState(prev => ({
        ...prev,
        list: mergeByIdFastPath(prev.list, incomingList),
        nextCursor: response.next_cursor,
        prevCursor: response.prev_cursor,
        hasMore: response.has_more && response.next_cursor !== null,
        isLoading: false,
        isInitialLoading: false,
        isLoadingMore: false,
        isFirstLoad: false,
      }));
      
      isLoadingRef.current = false;
    } catch (error) {
      if (cancelledRef.current) {
        isLoadingRef.current = false;
        return;
      }
      
      setState(prev => ({
        ...prev,
        isLoading: false,
        isInitialLoading: false,
        isLoadingMore: false,
        error: error instanceof Error ? error.message : '加载失败',
      }));
      
      isLoadingRef.current = false;
    }
  }, [state.isLoading, state.hasMore, state.nextCursor, fetchFunction, effectivePageSize, extraParams]);
  
  // 加载上一页（双向分页）
  const loadPrevious = useCallback(async () => {
    if (!bidirectional || state.isLoading || !state.prevCursor) {
      return;
    }
    
    cancelledRef.current = false;
    
    setState(prev => ({ ...prev, isLoading: true, isLoadingMore: true, error: null }));
    
    try {
      const response: CursorPaginationResponse<T> = await fetchFunction({
        cursor: state.prevCursor,
        direction: 'backward',
        pageSize: effectivePageSize,
        extraParams,
      });
      
      if (cancelledRef.current) return;
      
      const incomingList = normalizeList(response.list);
      setState(prev => ({
        ...prev,
        // 向前加载时，新数据放在前面
        list: mergeByIdFastPath(incomingList, prev.list),
        nextCursor: response.next_cursor,
        prevCursor: response.prev_cursor,
        hasMore: response.has_more,
        isLoading: false,
        isLoadingMore: false,
        isFirstLoad: false,
      }));
    } catch (error) {
      if (cancelledRef.current) return;
      
      setState(prev => ({
        ...prev,
        isLoading: false,
        isLoadingMore: false,
        error: error instanceof Error ? error.message : '加载失败',
      }));
    }
  }, [bidirectional, state.isLoading, state.prevCursor, fetchFunction, effectivePageSize, extraParams]);
  
  // 刷新数据
  const refresh = useCallback(async () => {
    cancelledRef.current = false;
    
    setState(prev => ({ ...prev, isRefreshing: true, error: null }));
    
    try {
      const response: CursorPaginationResponse<T> = await fetchFunction({
        cursor: undefined,
        direction: 'forward',
        pageSize: effectivePageSize,
        extraParams,
      });
      
      if (cancelledRef.current) return;
      
      const refreshedList = normalizeList(response.list);
      setState({
        list: mergeByIdFastPath([], refreshedList),
        nextCursor: response.next_cursor,
        prevCursor: response.prev_cursor,
        hasMore: response.has_more && response.next_cursor !== null,
        isLoading: false,
        isInitialLoading: false,
        isLoadingMore: false,
        isRefreshing: false,
        error: null,
        isFirstLoad: false,
      });
    } catch (error) {
      if (cancelledRef.current) return;
      
      setState(prev => ({
        ...prev,
        isRefreshing: false,
        error: error instanceof Error ? error.message : '刷新失败',
      }));
    }
  }, [fetchFunction, effectivePageSize, extraParams]);
  
  // 重置状态
  const reset = useCallback(() => {
    cancelledRef.current = true;
    autoLoadRef.current = false;
    isFirstLoadRef.current = true;
    isLoadingRef.current = false;
    setState({
      list: [],
      nextCursor: null,
      prevCursor: null,
      hasMore: true, // 重置后也设为 true，以便可以重新加载
      isLoading: false,
      isInitialLoading: false,
      isLoadingMore: false,
      isRefreshing: false,
      error: null,
      isFirstLoad: true,
    });
  }, []);
  
  // 设置数据（用于外部数据注入）
  const setList = useCallback(
    (
      list: T[],
      nextCursor: string | null,
      prevCursor: string | null,
      hasMore: boolean
    ) => {
      setState(prev => ({
        ...prev,
        list: mergeByIdFastPath([], normalizeList(list)),
        nextCursor,
        prevCursor,
        hasMore,
        isInitialLoading: false,
        isLoadingMore: false,
        isFirstLoad: false,
      }));
    },
    []
  );
  
  // 自动加载第一页
  useEffect(() => {
    // 使用 ref 防止重复加载，不依赖 loadMore 函数引用
    // 只检查 autoLoad 和 autoLoadRef，不再依赖 state.list.length
    if (!autoLoad || autoLoadRef.current) return;
    
    autoLoadRef.current = true;
    
    // 直接调用加载逻辑，避免依赖 loadMore 函数引用
    const loadInitialData = async () => {
      if (isLoadingRef.current) return;
      
      isLoadingRef.current = true;
      cancelledRef.current = false;
      
      setState(prev => ({ ...prev, isLoading: true, isInitialLoading: prev.list.length === 0, error: null }));
      
      try {
        const response: CursorPaginationResponse<T> = await fetchFunction({
          cursor: undefined,
          direction: 'forward',
          pageSize: effectivePageSize,
          extraParams,
        });
        
        if (cancelledRef.current) {
          isLoadingRef.current = false;
          return;
        }
        
        isFirstLoadRef.current = false;
        
        const initialList = normalizeList(response.list);
        setState(prev => ({
          ...prev,
          list: mergeByIdFastPath([], initialList),
          nextCursor: response.next_cursor,
          prevCursor: response.prev_cursor,
          hasMore: response.has_more && response.next_cursor !== null,
          isLoading: false,
          isInitialLoading: false,
          isLoadingMore: false,
          isFirstLoad: false,
        }));
        
        isLoadingRef.current = false;
      } catch (error) {
        if (cancelledRef.current) {
          isLoadingRef.current = false;
          return;
        }
        
        setState(prev => ({
          ...prev,
          isLoading: false,
          isInitialLoading: false,
          isLoadingMore: false,
          error: error instanceof Error ? error.message : '加载失败',
        }));
        
        isLoadingRef.current = false;
      }
    };
    
    loadInitialData();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoLoad]); // 只依赖 autoLoad，确保只执行一次
  
  return {
    ...state,
    loadMore,
    loadPrevious,
    refresh,
    reset,
    setList,
  };
}

export default useCursorPagination;