/**
 * 分页状态管理器
 * 
 * 提供分页状态的集中管理，包括：
 * - 分页状态跟踪（当前页、总加载数、是否有更多等）
 * - 页面缓存机制（避免重复加载相同页面）
 * - 加载锁机制（防止并发重复请求）
 * - 预加载功能（提前加载下一页数据）
 */

import {
  PaginationState,
  PageCache,
  PaginationConfig,
  LoadMoreResult,
  RefreshResult,
  PrefetchResult,
  FetchPageFunction,
  DEFAULT_PAGINATION_CONFIG,
  createInitialPaginationState,
  createPageCache,
  isCacheExpired,
} from './types';

/**
 * 分页状态管理器类
 * 管理多个分页键的状态，支持页面缓存和加载锁
 */
export class PaginationStateManager {
  // 分页状态存储：key -> PaginationState
  private states: Map<string, PaginationState> = new Map();
  
  // 页面缓存存储：key -> Map<pageNumber, PageCache>
  private pageCaches: Map<string, Map<number, PageCache>> = new Map();
  
  // 加载锁存储：key -> Set<pageNumber>
  private loadingLocks: Map<string, Set<number>> = new Map();
  
  // 配置存储：key -> PaginationConfig
  private configs: Map<string, PaginationConfig> = new Map();

  /**
   * 获取或创建分页状态
   * @param key 分页键（通常是会话ID或列表标识）
   * @param config 可选的配置
   * @returns 分页状态
   */
  getState(key: string, config?: Partial<PaginationConfig>): PaginationState {
    let state = this.states.get(key);
    if (!state) {
      const mergedConfig = this.getConfig(key, config);
      state = createInitialPaginationState(mergedConfig.pageSize);
      this.states.set(key, state);
    }
    return state;
  }

  /**
   * 更新分页状态
   * @param key 分页键
   * @param partialState 部分状态更新
   */
  setState(key: string, partialState: Partial<PaginationState>): void {
    const currentState = this.getState(key);
    this.states.set(key, {
      ...currentState,
      ...partialState,
    });
  }

  /**
   * 获取配置
   * @param key 分页键
   * @param overrideConfig 可选的覆盖配置
   * @returns 合并后的配置
   */
  getConfig(key: string, overrideConfig?: Partial<PaginationConfig>): PaginationConfig {
    const existingConfig = this.configs.get(key);
    if (overrideConfig) {
      const mergedConfig = {
        ...(existingConfig || DEFAULT_PAGINATION_CONFIG),
        ...overrideConfig,
      };
      this.configs.set(key, mergedConfig);
      return mergedConfig;
    }
    return existingConfig || DEFAULT_PAGINATION_CONFIG;
  }

  /**
   * 尝试获取加载锁
   * @param key 分页键
   * @param page 页码
   * @returns 是否成功获取锁
   */
  acquireLock(key: string, page: number): boolean {
    let locks = this.loadingLocks.get(key);
    if (!locks) {
      locks = new Set();
      this.loadingLocks.set(key, locks);
    }
    
    // 如果已经在加载中，返回 false
    if (locks.has(page)) {
      return false;
    }
    
    // 获取锁成功
    locks.add(page);
    
    // 更新状态为加载中
    this.setState(key, { isLoading: true, hasError: false, error: undefined });
    
    return true;
  }

  /**
   * 释放加载锁
   * @param key 分页键
   * @param page 页码
   */
  releaseLock(key: string, page: number): void {
    const locks = this.loadingLocks.get(key);
    if (locks) {
      locks.delete(page);
      
      // 如果没有正在加载的页面了，更新状态
      if (locks.size === 0) {
        this.setState(key, { isLoading: false });
      }
    }
  }

  /**
   * 检查是否正在加载指定页面
   * @param key 分页键
   * @param page 页码
   * @returns 是否正在加载
   */
  isPageLoading(key: string, page: number): boolean {
    const locks = this.loadingLocks.get(key);
    return locks ? locks.has(page) : false;
  }

  /**
   * 检查是否有任何页面正在加载
   * @param key 分页键
   * @returns 是否有页面正在加载
   */
  isAnyPageLoading(key: string): boolean {
    const locks = this.loadingLocks.get(key);
    return locks ? locks.size > 0 : false;
  }

  /**
   * 缓存页面数据
   * @param key 分页键
   * @param page 页码
   * @param data 页面数据
   * @param cursor 可选的分页游标
   */
  cachePage<T>(key: string, page: number, data: T[], cursor?: string | number | null): void {
    const config = this.getConfig(key);
    if (!config.enableCache) return;

    let caches = this.pageCaches.get(key);
    if (!caches) {
      caches = new Map();
      this.pageCaches.set(key, caches);
    }

    // 如果超过最大缓存页数，清理最旧的缓存
    if (caches.size >= config.maxCachedPages) {
      this.cleanupOldestCache(key);
    }

    caches.set(page, createPageCache(page, data, cursor));
  }

  /**
   * 获取缓存的页面数据
   * @param key 分页键
   * @param page 页码
   * @returns 缓存数据或 null
   */
  getCachedPage<T>(key: string, page: number): PageCache<T> | null {
    const config = this.getConfig(key);
    if (!config.enableCache) return null;

    const caches = this.pageCaches.get(key);
    if (!caches) return null;

    const cache = caches.get(page);
    if (!cache) return null;

    // 检查缓存是否过期
    if (isCacheExpired(cache, config.cacheTtl)) {
      caches.delete(page);
      return null;
    }

    return cache as PageCache<T>;
  }

  /**
   * 检查页面是否已缓存且未过期
   * @param key 分页键
   * @param page 页码
   * @returns 是否已缓存
   */
  isPageCached(key: string, page: number): boolean {
    return this.getCachedPage(key, page) !== null;
  }

  /**
   * 清除指定键的所有缓存
   * @param key 分页键
   */
  clearCache(key: string): void {
    this.pageCaches.delete(key);
  }

  /**
   * 重置分页状态
   * @param key 分页键
   * @param config 可选的新配置
   */
  reset(key: string, config?: Partial<PaginationConfig>): void {
    const mergedConfig = this.getConfig(key, config);
    this.states.set(key, createInitialPaginationState(mergedConfig.pageSize));
    this.clearCache(key);
    this.loadingLocks.delete(key);
  }

  /**
   * 删除分页状态
   * @param key 分页键
   */
  remove(key: string): void {
    this.states.delete(key);
    this.pageCaches.delete(key);
    this.loadingLocks.delete(key);
    this.configs.delete(key);
  }

  /**
   * 清理所有数据
   */
  clear(): void {
    this.states.clear();
    this.pageCaches.clear();
    this.loadingLocks.clear();
    this.configs.clear();
  }

  /**
   * 获取所有分页键
   * @returns 分页键数组
   */
  getKeys(): string[] {
    return Array.from(this.states.keys());
  }

  /**
   * 清理最旧的缓存
   * @param key 分页键
   */
  private cleanupOldestCache(key: string): void {
    const caches = this.pageCaches.get(key);
    if (!caches || caches.size === 0) return;

    let oldestPage = -1;
    let oldestTime = Infinity;

    Array.from(caches.entries()).forEach(([page, cache]) => {
      if (cache.cachedAt < oldestTime) {
        oldestTime = cache.cachedAt;
        oldestPage = page;
      }
    });

    if (oldestPage >= 0) {
      caches.delete(oldestPage);
    }
  }

  /**
   * 加载更多数据
   * @param key 分页键
   * @param fetchFunction 数据获取函数
   * @returns 加载结果
   */
  async loadMore<T>(
    key: string,
    fetchFunction: FetchPageFunction<T>
  ): Promise<LoadMoreResult<T>> {
    const state = this.getState(key);
    const config = this.getConfig(key);
    const nextPage = state.currentPage + 1;

    // 检查是否还有更多数据
    if (!state.hasMore) {
      return {
        success: true,
        data: [],
        hasMore: false,
        fromCache: false,
      };
    }

    // 尝试获取加载锁
    if (!this.acquireLock(key, nextPage)) {
      return {
        success: false,
        data: [],
        hasMore: state.hasMore,
        fromCache: false,
        error: 'Page is already loading',
      };
    }

    try {
      // 检查缓存
      const cachedPage = this.getCachedPage<T>(key, nextPage);
      if (cachedPage) {
        // 更新状态
        this.setState(key, {
          currentPage: nextPage,
          totalLoaded: state.totalLoaded + cachedPage.data.length,
          lastLoadTime: Date.now(),
        });

        return {
          success: true,
          data: cachedPage.data,
          hasMore: state.hasMore,
          fromCache: true,
        };
      }

      // 从数据源加载
      const result = await fetchFunction(nextPage, state.pageSize, state.cursor);

      // 缓存页面数据
      if (config.enableCache && result.data.length > 0) {
        this.cachePage(key, nextPage, result.data, result.cursor);
      }

      // 更新状态
      this.setState(key, {
        currentPage: nextPage,
        totalLoaded: state.totalLoaded + result.data.length,
        hasMore: result.hasMore,
        cursor: result.cursor,
        lastLoadTime: Date.now(),
        hasError: false,
        error: undefined,
      });

      return {
        success: true,
        data: result.data,
        hasMore: result.hasMore,
        fromCache: false,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      
      this.setState(key, {
        hasError: true,
        error: errorMessage,
      });

      return {
        success: false,
        data: [],
        hasMore: state.hasMore,
        fromCache: false,
        error: errorMessage,
      };
    } finally {
      this.releaseLock(key, nextPage);
    }
  }

  /**
   * 刷新数据（重新加载第一页）
   * @param key 分页键
   * @param fetchFunction 数据获取函数
   * @returns 刷新结果
   */
  async refresh<T>(
    key: string,
    fetchFunction: FetchPageFunction<T>
  ): Promise<RefreshResult<T>> {
    const state = this.getState(key);
    const config = this.getConfig(key);

    // 尝试获取加载锁
    if (!this.acquireLock(key, 1)) {
      return {
        success: false,
        data: [],
        hasMore: state.hasMore,
        error: 'Refresh already in progress',
      };
    }

    try {
      // 清除缓存
      this.clearCache(key);

      // 重置状态
      this.setState(key, {
        currentPage: 0,
        totalLoaded: 0,
        hasMore: true,
        cursor: null,
        hasError: false,
        error: undefined,
      });

      // 加载第一页
      const result = await fetchFunction(1, state.pageSize, null);

      // 缓存第一页
      if (config.enableCache && result.data.length > 0) {
        this.cachePage(key, 1, result.data, result.cursor);
      }

      // 更新状态
      this.setState(key, {
        currentPage: 1,
        totalLoaded: result.data.length,
        hasMore: result.hasMore,
        cursor: result.cursor,
        lastLoadTime: Date.now(),
      });

      return {
        success: true,
        data: result.data,
        hasMore: result.hasMore,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      
      this.setState(key, {
        hasError: true,
        error: errorMessage,
      });

      return {
        success: false,
        data: [],
        hasMore: state.hasMore,
        error: errorMessage,
      };
    } finally {
      this.releaseLock(key, 1);
    }
  }

  /**
   * 预加载指定页面
   * @param key 分页键
   * @param page 页码
   * @param fetchFunction 数据获取函数
   * @returns 预加载结果
   */
  async prefetch<T>(
    key: string,
    page: number,
    fetchFunction: FetchPageFunction<T>
  ): Promise<PrefetchResult<T>> {
    const config = this.getConfig(key);
    
    // 检查是否启用预加载
    if (!config.enablePrefetch) {
      return { success: false, error: 'Prefetch is disabled' };
    }

    // 检查是否已缓存
    if (this.isPageCached(key, page)) {
      return { success: true, data: this.getCachedPage<T>(key, page)?.data };
    }

    // 检查是否正在加载
    if (this.isPageLoading(key, page)) {
      return { success: false, error: 'Page is already loading' };
    }

    // 尝试获取加载锁
    if (!this.acquireLock(key, page)) {
      return { success: false, error: 'Failed to acquire lock' };
    }

    try {
      const result = await fetchFunction(page, config.pageSize, null);

      // 缓存数据
      if (config.enableCache && result.data.length > 0) {
        this.cachePage(key, page, result.data, result.cursor);
      }

      return {
        success: true,
        data: result.data,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      return {
        success: false,
        error: errorMessage,
      };
    } finally {
      this.releaseLock(key, page);
    }
  }

  /**
   * 检查是否应该预加载下一页
   * @param key 分页键
   * @param currentItemCount 当前已加载的条目数
   * @returns 是否应该预加载
   */
  shouldPrefetch(key: string, currentItemCount: number): boolean {
    const state = this.getState(key);
    const config = this.getConfig(key);

    if (!config.enablePrefetch) return false;
    if (!state.hasMore) return false;
    if (state.isLoading) return false;

    const nextPage = state.currentPage + 1;
    if (this.isPageLoading(key, nextPage)) return false;
    if (this.isPageCached(key, nextPage)) return false;

    // 检查是否达到预加载阈值
    const threshold = state.totalLoaded - config.prefetchThreshold;
    return currentItemCount >= threshold;
  }
}

// 导出单例实例
export const paginationStateManager = new PaginationStateManager();
