// Import NestJS module decorators and utilities
import { Module, Global } from '@nestjs/common';

// Import ConfigModule for environment configuration management
import { ConfigModule, ConfigService } from '@nestjs/config';

// Import Redis client library and types
import Redis, { RedisOptions } from 'ioredis';

// Import custom Redis service
import { RedisService } from './redis.service';

/**
 * RedisModule - Global module for Redis cache and messaging infrastructure
 *
 * This module provides a singleton Redis client instance and service to the entire application.
 * It's marked as @Global() to make Redis available across all modules without explicit imports.
 *
 * Key Features:
 * - Global singleton Redis client
 * - Environment-based configuration
 * - Connection resilience with retry strategy
 * - Custom RedisService wrapper for business logic
 *
 * Architecture Pattern:
 * - Factory Provider Pattern: Creates Redis client with dynamic configuration
 * - Global Module Pattern: Makes Redis available application-wide
 * - Configuration Pattern: Externalizes Redis settings
 *
 * Purpose:
 * - Centralized Redis connection management
 * - Consistent Redis configuration across the app
 * - Abstraction layer for Redis operations via RedisService
 */
@Global()
@Module({
  /**
   * imports - External modules required by this module
   *
   * ConfigModule: Provides ConfigService for reading environment variables
   * - Required to get Redis connection parameters from .env/config files
   * - Supports different configurations per environment (dev, prod, test)
   */
  imports: [ConfigModule],

  /**
   * providers - Injectable services and factories available within this module
   *
   * 1. Factory Provider for 'REDIS_CLIENT':
   *    - Creates Redis client instance with configuration from ConfigService
   *    - Uses factory pattern for dynamic initialization
   *    - Provides retry strategy and connection resilience
   *
   * 2. RedisService: Custom service wrapping Redis operations
   *    - Provides business logic methods for cache operations
   *    - Abstracts raw Redis client for better maintainability
   *    - Can add metrics, logging, or custom logic
   */
  providers: [
    {
      /**
       * provide: 'REDIS_CLIENT' - Token for dependency injection
       *
       * This is a custom provider token that will be used to inject the Redis client
       * into other services using @Inject('REDIS_CLIENT')
       */
      provide: 'REDIS_CLIENT',

      /**
       * useFactory - Factory function that creates Redis client instance
       *
       * This factory reads configuration from environment variables and creates
       * a properly configured Redis client instance.
       *
       * @param configService - Injected ConfigService for reading environment variables
       * @returns New Redis client instance
       */
      useFactory: (configService: ConfigService) => {
        // Redis connection options with defaults and environment-specific values
        const options: RedisOptions = {
          // Unix socket path (alternative to host/port)
          path: configService.get<string>('REDIS_SOCKET_PATH'),

          // Redis server hostname (default: localhost)
          host: configService.get<string>('REDIS_HOST', 'localhost'),

          // Redis server port (default: 6379)
          port: configService.get<number>('REDIS_PORT', 6379),

          // Redis authentication password (optional)
          password: configService.get<string>('REDIS_PASSWORD'),

          // Redis database number (default: 0)
          db: configService.get<number>('REDIS_DB', 0),

          // Key prefix for all Redis keys (helps with namespacing)
          keyPrefix: configService.get<string>('REDIS_KEY_PREFIX', 'app:'),

          // Disable ready check for faster connections
          enableReadyCheck: false,

          // Allow unlimited retries for requests
          maxRetriesPerRequest: null,

          /**
           * retryStrategy - Custom retry logic for connection failures
           *
           * Implements exponential backoff with jitter:
           * - First retry: 50ms
           * - Second retry: 100ms
           * - Third retry: 150ms
           * - Max delay: 2000ms (2 seconds)
           *
           * @param times - Number of retry attempts
           * @returns Delay in milliseconds before next retry
           */
          retryStrategy: (times) => {
            // Exponential backoff with max cap
            return Math.min(times * 50, 2000);
          },
        };

        // Create and return Redis client instance
        // return new Redis(options);
        return null;
      },

      /**
       * inject - Dependencies required by the factory function
       *
       * ConfigService is injected to read environment variables
       */
      inject: [ConfigService],
    },

    // Custom Redis service for business logic
    RedisService,
  ],

  /**
   * exports - Providers that should be available to other modules
   *
   * 1. 'REDIS_CLIENT': Raw Redis client for direct access
   * 2. RedisService: Custom service for higher-level operations
   *
   * Since this is a @Global() module, these are available throughout the app
   */
  exports: ['REDIS_CLIENT', RedisService],
})
export class RedisModule {}
