import Redis from 'ioredis';
import { singleton } from 'tsyringe';

interface CacheOptions {
  ttl?: number; // 过期时间（秒）
  tags?: string[]; // 缓存标签，用于批量清除
  priority?: 'low' | 'medium' | 'high'; // 缓存优先级
}

interface CacheItem {
  value: any;
  expiry: number;
  tags: string[];
  priority: 'low' | 'medium' | 'high';
  createdAt: number;
  lastAccessed: number;
  accessCount: number;
}

@singleton()
export class CacheService {
  private memoryCache: Map<string, CacheItem> = new Map();
  private redisClient: Redis | null = null;
  private memoryCacheSize: number = 1000; // 内存缓存大小限制
  private memoryCacheCleanupInterval: NodeJS.Timeout;

  constructor() {
    this.initializeRedis();
    this.startMemoryCacheCleanup();
  }

  private async initializeRedis() {
    try {
      const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
      this.redisClient = new Redis(redisUrl);
      await this.redisClient.ping();
      console.log('Redis connected successfully');
    } catch (error) {
      console.warn('Failed to connect to Redis, falling back to memory cache:', error);
      this.redisClient = null;
    }
  }

  private startMemoryCacheCleanup() {
    // 每5分钟清理一次过期的内存缓存
    this.memoryCacheCleanupInterval = setInterval(() => {
      this.cleanupMemoryCache();
    }, 5 * 60 * 1000);
  }

  private cleanupMemoryCache() {
    const now = Date.now();
    const keysToDelete: string[] = [];

    // 删除过期的缓存项
    for (const [key, item] of this.memoryCache.entries()) {
      if (item.expiry < now) {
        keysToDelete.push(key);
      }
    }

    keysToDelete.forEach(key => this.memoryCache.delete(key));

    // 如果缓存大小超过限制，删除优先级低的缓存项
    if (this.memoryCache.size > this.memoryCacheSize) {
      const items = Array.from(this.memoryCache.entries())
        .sort((a, b) => {
          // 首先按优先级排序
          const priorityOrder = { low: 0, medium: 1, high: 2 };
          const priorityDiff = priorityOrder[a[1].priority] - priorityOrder[b[1].priority];
          if (priorityDiff !== 0) return priorityDiff;
          
          // 优先级相同，按访问时间排序（最近访问的优先保留）
          return b[1].lastAccessed - a[1].lastAccessed;
        });

      const itemsToKeep = items.slice(0, this.memoryCacheSize);
      const keysToKeep = new Set(itemsToKeep.map(([key]) => key));

      for (const key of this.memoryCache.keys()) {
        if (!keysToKeep.has(key)) {
          this.memoryCache.delete(key);
        }
      }
    }
  }

  /**
   * 设置缓存
   */
  async set<T>(key: string, value: T, options: CacheOptions = {}): Promise<void> {
    const { ttl = 3600, tags = [], priority = 'medium' } = options;
    const expiry = Date.now() + (ttl * 1000);

    // 存储到内存缓存
    this.memoryCache.set(key, {
      value,
      expiry,
      tags,
      priority,
      createdAt: Date.now(),
      lastAccessed: Date.now(),
      accessCount: 1,
    });

    // 存储到 Redis（如果可用）
    if (this.redisClient) {
      try {
        const serializedValue = JSON.stringify(value);
        await this.redisClient.setex(key, ttl, serializedValue);
        
        // 存储标签
        if (tags.length > 0) {
          for (const tag of tags) {
            await this.redisClient.sadd(`tag:${tag}`, key);
          }
        }
      } catch (error) {
        console.warn('Failed to set Redis cache:', error);
      }
    }
  }

  /**
   * 获取缓存
   */
  async get<T>(key: string): Promise<T | null> {
    // 先从内存缓存获取
    const memoryItem = this.memoryCache.get(key);
    if (memoryItem) {
      // 检查是否过期
      if (memoryItem.expiry > Date.now()) {
        // 更新访问时间和访问次数
        memoryItem.lastAccessed = Date.now();
        memoryItem.accessCount++;
        return memoryItem.value as T;
      } else {
        // 过期，删除
        this.memoryCache.delete(key);
      }
    }

    // 从 Redis 获取（如果可用）
    if (this.redisClient) {
      try {
        const serializedValue = await this.redisClient.get(key);
        if (serializedValue) {
          const value = JSON.parse(serializedValue);
          // 同步到内存缓存
          const ttl = await this.redisClient.ttl(key);
          if (ttl > 0) {
            this.memoryCache.set(key, {
              value,
              expiry: Date.now() + (ttl * 1000),
              tags: [], // 从 Redis 中获取标签比较复杂，这里简化处理
              priority: 'medium',
              createdAt: Date.now(),
              lastAccessed: Date.now(),
              accessCount: 1,
            });
          }
          return value as T;
        }
      } catch (error) {
        console.warn('Failed to get Redis cache:', error);
      }
    }

    return null;
  }

  /**
   * 删除缓存
   */
  async delete(key: string): Promise<void> {
    // 从内存缓存删除
    this.memoryCache.delete(key);

    // 从 Redis 删除（如果可用）
    if (this.redisClient) {
      try {
        await this.redisClient.del(key);
      } catch (error) {
        console.warn('Failed to delete Redis cache:', error);
      }
    }
  }

  /**
   * 按标签删除缓存
   */
  async deleteByTag(tag: string): Promise<void> {
    // 从内存缓存删除
    const keysToDelete: string[] = [];
    for (const [key, item] of this.memoryCache.entries()) {
      if (item.tags.includes(tag)) {
        keysToDelete.push(key);
      }
    }
    keysToDelete.forEach(key => this.memoryCache.delete(key));

    // 从 Redis 删除（如果可用）
    if (this.redisClient) {
      try {
        const keys = await this.redisClient.smembers(`tag:${tag}`);
        if (keys.length > 0) {
          await this.redisClient.del(...keys);
          await this.redisClient.del(`tag:${tag}`);
        }
      } catch (error) {
        console.warn('Failed to delete Redis cache by tag:', error);
      }
    }
  }

  /**
   * 清除所有缓存
   */
  async clear(): Promise<void> {
    // 清除内存缓存
    this.memoryCache.clear();

    // 清除 Redis 缓存（如果可用）
    if (this.redisClient) {
      try {
        await this.redisClient.flushdb();
      } catch (error) {
        console.warn('Failed to clear Redis cache:', error);
      }
    }
  }

  /**
   * 获取缓存统计信息
   */
  getStats(): {
    memoryCacheSize: number;
    memoryCacheKeys: string[];
    redisConnected: boolean;
  } {
    return {
      memoryCacheSize: this.memoryCache.size,
      memoryCacheKeys: Array.from(this.memoryCache.keys()),
      redisConnected: this.redisClient !== null,
    };
  }

  /**
   * 关闭缓存服务
   */
  async close(): Promise<void> {
    clearInterval(this.memoryCacheCleanupInterval);
    if (this.redisClient) {
      try {
        await this.redisClient.quit();
      } catch (error) {
        console.warn('Failed to close Redis connection:', error);
      }
    }
  }
}

// 单例实例
export const cacheService = new CacheService();
