import { CacheInterceptor } from '@nestjs/cache-manager';
import { ExecutionContext, Injectable } from '@nestjs/common';

/**
 * Custom HTTP Cache Interceptor that extends NestJS's CacheInterceptor.
 *
 * This interceptor provides fine-grained control over HTTP request caching,
 * allowing selective caching based on request method and URL path.
 * It's particularly useful for caching GET requests while excluding specific routes.
 *
 * Key Features:
 * - Only caches GET requests by default
 * - Allows exclusion of specific URL paths from caching
 * - Extends NestJS's built-in cache management capabilities
 *
 * @extends CacheInterceptor
 *
 * @example
 * // Apply globally in main.ts or app.module.ts
 * app.useGlobalInterceptors(new HttpCacheInterceptor());
 *
 * // Or apply to specific controller/route
 * @UseInterceptors(HttpCacheInterceptor)
 * @Controller('products')
 */
@Injectable()
export class HttpCacheInterceptor extends CacheInterceptor {
  /**
   * Determines the cache key for a given request based on the URL.
   * This method overrides the parent's trackBy to add custom caching logic.
   *
   * How it works:
   * 1. Extracts the HTTP request from the execution context
   * 2. Checks if the request is a GET request
   * 3. Checks if the request URL is in the exclude list
   * 4. Returns the request URL as cache key if cachable, undefined otherwise
   *
   * @param context - The execution context containing request details
   * @returns The cache key (request URL) if the request should be cached, undefined otherwise
   *
   * @note When undefined is returned, the request bypasses the cache entirely
   */
  trackBy(context: ExecutionContext): string | undefined {
    // Get the HTTP request object from the execution context
    const request = context.switchToHttp().getRequest();

    // Get the HTTP adapter to access platform-agnostic request methods
    const { httpAdapter } = this.httpAdapterHost;

    // Check if the request method is GET (only cache GET requests)
    const isGetRequest = httpAdapter.getRequestMethod(request) === 'GET';

    // Define paths that should be excluded from caching
    // Add routes here that should never be cached (e.g., real-time data, user-specific content)
    const excludePaths = [
      // Example: '/api/auth/user-profile',
      // Example: '/api/real-time/updates'
    ];

    /**
     * Determine if request should bypass caching:
     * 1. If it's NOT a GET request, OR
     * 2. If it IS a GET request but the URL is in the exclude list
     */
    if (
      !isGetRequest ||
      (isGetRequest &&
        excludePaths.includes(httpAdapter.getRequestUrl(request)))
    ) {
      // Return undefined to bypass caching for this request
      return undefined;
    }

    /**
     * Return the request URL as the cache key
     * This means identical URLs will return the same cached response
     * Note: Query parameters are included in the URL, so different query params = different cache keys
     */
    return httpAdapter.getRequestUrl(request);
  }
}

/**
 * Usage Considerations:
 *
 * 1. Cache Invalidation: This interceptor uses URL-based caching. Cache invalidation
 *    happens automatically when the cache TTL expires (configured in CacheModule).
 *
 * 2. Query Parameters: Different query parameters create different cache keys.
 *    Example: '/api/products?page=1' and '/api/products?page=2' are cached separately.
 *
 * 3. Dynamic Paths: Paths with parameters (e.g., '/api/users/:id') are cached individually.
 *    Each unique ID gets its own cache entry.
 *
 * 4. Security: Be cautious about caching user-specific data. Consider adding
 *    authentication checks or excluding authenticated routes.
 *
 * 5. Performance: For optimal performance, exclude frequently changing data
 *    or add shorter TTLs for those routes in your CacheModule configuration.
 */
