import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { APP_GUARD, APP_INTERCEPTOR, RouterModule } from '@nestjs/core';
import { CacheInterceptor, CacheModule } from '@nestjs/cache-manager';
import { ResponseTimeInterceptor } from './interceptors/response-time.interceptor';
import { TransformInterceptor } from './interceptors/transform.interceptor';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

// Middleware & Services
import { RolePermissionsMiddleware } from './middlewares/role-permissions.middleware';
import { RedisService } from './modules/backend/redis/redis.service';

// Backend Modules
import { GlobalModule } from './modules/backend/global/global.module';
import { RedisModule } from './modules/backend/redis/redis.module';

import { JwtGlobalModule } from './config/jwt-global.module';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { DevicesModule } from './modules/backend/devices/devices.module';
import { DeviceAssignmentsModule } from './modules/backend/device-assignments/device-assignments.module';
import { UsersModule } from './modules/backend/users/users.module';
import { VendorsModule } from './modules/backend/vendors/vendors.module';
import { UserModule } from './modules/backend/user/user.module';
import { AuthorizationModule } from './modules/authorizations/authorization.module';

const BACKEND_ROUTES = [
  { path: 'user', module: UserModule },
  { path: 'global', module: GlobalModule },
  { path: 'devices', module: DevicesModule },
  { path: 'device-assignments', module: DeviceAssignmentsModule },
  { path: 'users', module: UsersModule },
  { path: 'vendors', module: VendorsModule },
  { path: 'authorization', module: AuthorizationModule },
];

/**
 * Root application module for NestJS.
 *
 * This module serves as the entry point for the application, configuring:
 * - Database connections (MySQL via TypeORM)
 * - Global modules (Config, Cache, Static file serving)
 * - API routing structure (Frontend/Backend separation)
 * - Global interceptors (Caching, Response transformation, Performance monitoring)
 * - Application-wide middleware (Role-based permissions)
 *
 * The application follows a clear separation between:
 * - Frontend API routes (/api/frontend/*) - for customer-facing features
 * - Backend API routes (/api/backend/*) - for administrative/management features
 *
 * @example
 * // Frontend API endpoints:
 * // GET /api/frontend/home
 * // POST /api/frontend/student/register
 *
 * @example
 * // Backend API endpoints:
 * // GET /api/backend/user
 * // POST /api/backend/visa-commission
 */
@Module({
  imports: [
    ThrottlerModule.forRoot({
      throttlers: [
        {
          ttl: 60, // time window in seconds
          limit: 10, // max requests per window
        },
      ],
    }),
    // Configuration module - loads environment variables from .env file
    // Global scope makes ConfigService available throughout the app
    GlobalModule,
    ConfigModule.forRoot({ isGlobal: true, envFilePath: `.env` }),
    JwtModule.registerAsync({
      global: true,
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        secret: config.get('JWT_SECRET'),
        signOptions: { expiresIn: '15m' },
      }),
    }),

    // Cache module for application-wide caching
    // Can be configured with different stores (memory, Redis, etc.)
    CacheModule.register(),

    // Serve static files from the uploads directory
    // Makes uploaded files accessible at /uploads/* URLs
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'uploads'),
      serveRoot: '/uploads',
    }),

    // Database configuration using TypeORM with MySQL
    // Configuration is loaded asynchronously from environment variables
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        type: 'mysql',
        host: config.get<string>('DB_HOST'),
        port: config.get<number>('DB_PORT'),
        username: config.get<string>('DB_USER'),
        password: config.get<string>('DB_PASSWORD'),
        database: config.get<string>('DB_NAME'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'], // Auto-load all entity files
        synchronize: false, // IMPORTANT: Keep false in production to prevent auto schema changes
      }),
    }),

    // Router configuration for API structure
    // Creates clear separation between frontend and backend routes
    RouterModule.register([
      // { path: 'api/frontend', children: FRONTEND_ROUTES }, // All frontend routes prefixed with /api/frontend
      { path: 'api/backend', children: BACKEND_ROUTES }, // All backend routes prefixed with /api/backend
    ]),
    ...BACKEND_ROUTES.map((r) => r.module),
    RedisModule, // Redis module for caching and session management
  ],

  // Root application controller
  controllers: [AppController],

  // Application-wide providers and interceptors
  providers: [
    AppService, // Main application service
    JwtService, // JWT token service for authentication
    RedisService, // Redis service for caching/sessions

    // Global interceptors - apply to all HTTP requests
    { provide: APP_INTERCEPTOR, useClass: CacheInterceptor }, // Caching interceptor
    { provide: APP_INTERCEPTOR, useClass: ResponseTimeInterceptor }, // Response time tracking
    { provide: APP_INTERCEPTOR, useClass: TransformInterceptor }, // Response standardization
    {
      provide: APP_GUARD,
      useClass: ThrottlerGuard,
    },
  ],
})
export class AppModule {
  /**
   * Configure application middleware
   * Middleware runs before routes are processed
   *
   * @param consumer - Middleware consumer for applying middleware to routes
   */
  // configure(consumer: MiddlewareConsumer) {
  //   consumer
  //     .apply(RolePermissionsMiddleware) // Apply role-based permission middleware
  //     .exclude({
  //       // Exclude session validation endpoint from permission checks
  //       // This allows users to validate their session without having specific permissions
  //       // path: 'api/backend/global/validate-session',
  //       path: 'api/backend/global/sso/login',
  //       method: RequestMethod.POST,
  //     })
  //     .forRoutes('*'); // Apply to all routes in the application
  // }
}
