/**
 * In-memory response cache with configurable TTL
 * Cache keys are generated from tool name + sorted arguments
 */

interface CacheEntry<T> {
  value: T;
  expiresAt: number;
}

export interface CacheConfig {
  /** Default TTL for analytics queries (15 min) */
  analyticsTTL?: number;
  /** Default TTL for sitemap data (5 min) */
  sitemapsTTL?: number;
  /** Default TTL for URL inspection (30 min) */
  inspectionTTL?: number;
  /** Default TTL for property listings (60 min) */
  propertiesTTL?: number;
}

export class Cache {
  private store = new Map<string, CacheEntry<any>>();
  private config: Required<CacheConfig>;

  constructor(config: CacheConfig = {}) {
    this.config = {
      analyticsTTL: config.analyticsTTL ?? 15 * 60 * 1000, // 15 min
      sitemapsTTL: config.sitemapsTTL ?? 5 * 60 * 1000,    // 5 min
      inspectionTTL: config.inspectionTTL ?? 30 * 60 * 1000, // 30 min
      propertiesTTL: config.propertiesTTL ?? 60 * 60 * 1000  // 60 min
    };
  }

  /**
   * Generate cache key from tool name and arguments
   * Arguments are sorted to ensure consistent keys
   */
  private generateKey(toolName: string, args: Record<string, any>): string {
    const sortedArgs = Object.keys(args)
      .sort()
      .reduce((acc, key) => {
        acc[key] = args[key];
        return acc;
      }, {} as Record<string, any>);
    
    return `${toolName}:${JSON.stringify(sortedArgs)}`;
  }

  /**
   * Get TTL for a specific tool category
   */
  private getTTL(toolName: string): number {
    if (toolName.includes('analytics') || toolName.includes('compare') || 
        toolName.includes('movers') || toolName.includes('mobile') || 
        toolName.includes('country') || toolName.includes('intelligence') ||
        toolName.includes('quick_wins') || toolName.includes('cannibalization') ||
        toolName.includes('decay') || toolName.includes('clustering')) {
      return this.config.analyticsTTL;
    }
    
    if (toolName.includes('sitemap')) {
      return this.config.sitemapsTTL;
    }
    
    if (toolName.includes('inspect')) {
      return this.config.inspectionTTL;
    }
    
    if (toolName.includes('properties') || toolName.includes('property')) {
      return this.config.propertiesTTL;
    }
    
    // Default to analytics TTL
    return this.config.analyticsTTL;
  }

  /**
   * Get cached value if it exists and hasn't expired
   */
  get<T>(toolName: string, args: Record<string, any>): T | undefined {
    const key = this.generateKey(toolName, args);
    const entry = this.store.get(key);
    
    if (!entry) return undefined;
    
    if (Date.now() > entry.expiresAt) {
      this.store.delete(key);
      return undefined;
    }
    
    return entry.value as T;
  }

  /**
   * Set cache value with TTL based on tool type
   */
  set<T>(toolName: string, args: Record<string, any>, value: T, customTTL?: number): void {
    const key = this.generateKey(toolName, args);
    const ttl = customTTL ?? this.getTTL(toolName);
    
    this.store.set(key, {
      value,
      expiresAt: Date.now() + ttl
    });
  }

  /**
   * Check if cache has valid entry
   */
  has(toolName: string, args: Record<string, any>): boolean {
    return this.get(toolName, args) !== undefined;
  }

  /**
   * Clear all cache entries
   */
  clear(): void {
    this.store.clear();
  }

  /**
   * Clear all entries matching a tool name prefix
   */
  clearByPrefix(prefix: string): void {
    for (const key of this.store.keys()) {
      if (key.startsWith(prefix)) {
        this.store.delete(key);
      }
    }
  }

  /**
   * Remove expired entries (called periodically)
   */
  prune(): void {
    const now = Date.now();
    for (const [key, entry] of this.store.entries()) {
      if (now > entry.expiresAt) {
        this.store.delete(key);
      }
    }
  }

  /**
   * Get cache statistics
   */
  getStats(): { size: number; keys: string[] } {
    return {
      size: this.store.size,
      keys: Array.from(this.store.keys())
    };
  }
}
