/**
 * 统一缓存服务
 * 提供标准化的缓存操作，包括缓存键生成、读写、过期时间管理等
 */

import RedisService from './RedisService';
import { logger } from '../utils/logger';

export interface CacheOptions {
  ttl?: number; // 缓存过期时间（秒）
  prefix?: string; // 缓存键前缀
  namespace?: string; // 命名空间
}

export class CacheService {
  /**
   * 生成缓存键
   * @param key 基础键名
   * @param options 缓存选项
   * @param params 额外参数（用于生成唯一键）
   */
  static generateKey(key: string, options: CacheOptions = {}, ...params: (string | number | undefined)[]): string {
    const prefix = options.prefix || 'cache';
    const namespace = options.namespace ? `${options.namespace}:` : '';
    const paramsString = params
      .filter((p): p is string | number => p !== undefined)
      .map(p => String(p))
      .join(':');
    
    return `${prefix}:${namespace}${key}${paramsString ? `:${paramsString}` : ''}`;
  }

  /**
   * 获取缓存
   * @param key 缓存键
   * @param options 缓存选项
   * @param params 额外参数（用于生成唯一键）
   */
  static async get<T>(key: string, options: CacheOptions = {}, ...params: (string | number | undefined)[]): Promise<T | null> {
    try {
      const cacheKey = this.generateKey(key, options, ...params);
      const value = await RedisService.get(cacheKey);
      return value as T | null;
    } catch (error) {
      logger.warn(`[CacheService] Failed to get cache: ${(error as any).message}`);
      return null;
    }
  }

  /**
   * 设置缓存
   * @param key 缓存键
   * @param value 缓存值
   * @param options 缓存选项
   * @param params 额外参数（用于生成唯一键）
   */
  static async set<T>(key: string, value: T, options: CacheOptions = {}, ...params: (string | number | undefined)[]): Promise<boolean> {
    try {
      const cacheKey = this.generateKey(key, options, ...params);
      const ttl = options.ttl || 3600; // 默认1小时
      return await RedisService.set(cacheKey, value, ttl);
    } catch (error) {
      logger.warn(`[CacheService] Failed to set cache: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 删除缓存
   * @param key 缓存键
   * @param options 缓存选项
   * @param params 额外参数（用于生成唯一键）
   */
  static async delete(key: string, options: CacheOptions = {}, ...params: (string | number | undefined)[]): Promise<boolean> {
    try {
      const cacheKey = this.generateKey(key, options, ...params);
      return await RedisService.del(cacheKey);
    } catch (error) {
      logger.warn(`[CacheService] Failed to delete cache: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 批量删除缓存
   * @param keys 缓存键列表
   * @param options 缓存选项
   */
  static async deleteMultiple(keys: string[], options: CacheOptions = {}): Promise<boolean> {
    try {
      const cacheKeys = keys.map(key => this.generateKey(key, options));
      return await RedisService.delMultiple(cacheKeys);
    } catch (error) {
      logger.warn(`[CacheService] Failed to delete multiple caches: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 删除匹配模式的缓存
   * @param pattern 键模式（支持通配符）
   * @param options 缓存选项
   */
  static async deletePattern(pattern: string, options: CacheOptions = {}): Promise<boolean> {
    try {
      const prefix = options.prefix || 'cache';
      const namespace = options.namespace ? `${options.namespace}:` : '';
      const fullPattern = `${prefix}:${namespace}${pattern}`;
      
      return await RedisService.deletePattern(fullPattern);
    } catch (error) {
      logger.warn(`[CacheService] Failed to delete pattern: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 缓存包装器
   * @param key 缓存键
   * @param fn 要执行的函数
   * @param options 缓存选项
   * @param params 额外参数（用于生成唯一键）
   */
  static async wrap<T>(
    key: string,
    fn: () => Promise<T>,
    options: CacheOptions = {},
    ...params: (string | number | undefined)[]
  ): Promise<T> {
    // 尝试从缓存获取
    const cached = await this.get<T>(key, options, ...params);
    if (cached !== null) {
      return cached;
    }

    // 执行函数获取结果
    const result = await fn();

    // 设置缓存
    await this.set(key, result, options, ...params);

    return result;
  }

  /**
   * 清除命名空间下的所有缓存
   * @param namespace 命名空间
   * @param options 缓存选项
   */
  static async clearNamespace(namespace: string, options: CacheOptions = {}): Promise<boolean> {
    return this.deletePattern('*', { ...options, namespace });
  }

  /**
   * 清除所有缓存
   * @param options 缓存选项
   */
  static async clearAll(options: CacheOptions = {}): Promise<boolean> {
    return this.deletePattern('*', options);
  }
}

export default CacheService;
