import { globalCache } from './cache';

type CacheStrategy = 'session' | 'local' | 'memory';

interface CacheOptions {
  strategy?: CacheStrategy;
  ttl?: number; // 过期时间（毫秒）
}

export class CachedRequest {
  private cacheKey: string;
  private fetchData: () => Promise<any>;
  private options: CacheOptions;

  constructor(cacheKey: string, fetchData: () => Promise<any>, options: CacheOptions = {}) {
    this.cacheKey = cacheKey;
    this.fetchData = fetchData;
    this.options = {
      strategy: 'session',
      ttl: 0,
      ...options,
    };
  }

  private getCache(): any {
    const { strategy } = this.options;

    switch (strategy) {
      case 'local':
        return localStorage;
      case 'memory':
        return globalCache;
      case 'session':
      default:
        return sessionStorage;
    }
  }

  private getCachedData() {
    const cache = this.getCache();
    const data = this.options.strategy === 'memory' ? cache.get(this.cacheKey) : cache.getItem(this.cacheKey);

    if (!data) return null;

    const parsed = JSON.parse(data);

    // 检查是否过期
    if (this.options.ttl && parsed.timestamp) {
      const isExpired = Date.now() - parsed.timestamp > this.options.ttl;
      if (isExpired) {
        this.clearCache();
        return null;
      }
    }

    return parsed.data;
  }

  private setCachedData(data: any) {
    const cache = this.getCache();
    const value = JSON.stringify({
      data,
      timestamp: Date.now(),
    });

    if (this.options.strategy === 'memory') {
      cache.set(this.cacheKey, value);
    } else {
      cache.setItem(this.cacheKey, value);
    }
  }

  clearCache() {
    const cache = this.getCache();
    if (this.options.strategy === 'memory') {
      cache.delete(this.cacheKey);
    } else {
      cache.removeItem(this.cacheKey);
    }
  }

  fetch(forceRefresh = false) {
    const cachedData = !forceRefresh && this.getCachedData();
    if (cachedData) return Promise.resolve(cachedData);

    const globalItem = globalCache.get(this.cacheKey);
    if (globalItem?.promise) {
      return globalItem.promise;
    }

    const newPromise = this.fetchData()
      .then(({ data }: any) => {
        this.setCachedData(data);
        return data;
      })
      .finally(() => {
        globalCache.delete(this.cacheKey);
      });

    globalCache.set(this.cacheKey, { promise: newPromise });
    return newPromise;
  }
}
