import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
import { ConfigService } from '@nestjs/config';
import { HttpStatus, Logger, ValidationPipe } from '@nestjs/common';
import { CustomException } from './utils/response';
import { GlobalModule } from './modules/backend/global/global.module';
import { VisaCommissionModule } from './modules/backend/visa-commission/visa-commission.module';
import { HomeModule } from './modules/frontend/home/home.module';
import { LandingPagesModule } from './modules/frontend/landing-pages/landing-pages.module';
import { StudentModule } from './modules/frontend/student/student.module';
import { CoursePortalModule } from './modules/backend/course-portal/course-portal.module';
import { CommissionResponseReasonModule } from './modules/backend/masters/commission-response-reason/commission-response-reason.module';
import { CommissionDifferenceReasonModule } from './modules/backend/masters/commission-difference-reason/commission-difference-reason.module';
// import { ReleaseNotesModule } from './modules/backend/masters/release-notes/release-nodes.module';
import { MenuActionsModule } from './modules/backend/menu-actions/menu-actions.module';
import { MenuGroupsModule } from './modules/backend/menu-groups/menu-groups.module';
import { MenusModule } from './modules/backend/menus/menus.module';
import { QuoteMasterModule } from './modules/backend/quote-master/quote-master.module';
import { UserModule } from './modules/backend/user/user.module';
import { UserSettingsModule } from './modules/backend/user-settings/user-settings.module';
import { VisaCommissionEnquiryModule } from './modules/backend/visa-commission-enquiry/visa-commission-enquiry.module';
import './utils/common/global-utility';
import { VisaCommissionReceivedModule } from './modules/backend/visa-commission-received/visa-commission-received.module';
import { VisaBonusReceivedModule } from './modules/backend/visa-bonus-received/visa-bonus-received.module';
import { SubAgentCommissionModule } from './modules/backend/sub-agent-commission/sub-agent-commission.module';
import { SubAgentBonusPaidModule } from './modules/backend/sub-agent-bonus-paid/sub-agent-bonus-paid.module';
import { WinstonModule } from 'nest-winston';
import { winstonConfig } from './logger/winston.config';
import * as session from 'express-session';
import * as cookieParser from 'cookie-parser';
import { UsersModule } from './modules/backend/users/users.module';
import { DevicesModule } from './modules/backend/devices/devices.module';
import { VendorsModule } from './modules/backend/vendors/vendors.module';
import { DeviceAssignmentsModule } from './modules/backend/device-assignments/device-assignments.module';
import { AuthorizationModule } from './modules/authorizations/authorization.module';

/**
 * Bootstrap function - Entry point of the NestJS application.
 * This function initializes and configures the application server.
 *
 * Key responsibilities:
 * 1. Application initialization with logging configuration
 * 2. CORS configuration for cross-origin requests
 * 3. Swagger API documentation setup for different module groups
 * 4. Global validation pipe configuration
 * 5. Server startup
 *
 * @async
 * @returns {Promise<void>}
 *
 * @example
 * // Application starts and listens on configured port (default: 3001)
 * // API Documentation available at:
 * // - Frontend: http://localhost:3001/api/frontend/docs
 * // - Backend: http://localhost:3001/api/backend/docs
 * // - Visa Commission: http://localhost:3001/api/visa-commission/docs
 */
async function bootstrap() {
  // Create bootstrap logger for startup process
  const logger = new Logger('Bootstrap');

  // Debug mode: Log all environment variables when DEBUG=true
  if (process.env.DEBUG?.toLowerCase() === 'true') {
    logger.log('--- ENVIRONMENT VARIABLES ---');
    Object.entries(process.env).forEach(([key, value]) =>
      logger.log(`${key} = ${value}`),
    );
    logger.log('>>>----------------------------->');
  }

  // Initialize the NestJS application with AppModule as root module
  // bufferLogs: true buffers logs until a custom logger is attached
  const app = await NestFactory.create(AppModule, {
    bufferLogs: true,
  });

  app.use(cookieParser());

  app.use(
    session({
      secret: process.env.SESSION_SECRET || 'your-secret-key',
      resave: false,
      saveUninitialized: false,
      cookie: {
        maxAge: 24 * 60 * 60 * 1000,
        httpOnly: true,
        secure: false, // set to true only in production with HTTPS
        sameSite: 'lax',
      },
    }),
  );
  // Configure Winston logger for structured logging
  const appLogger = WinstonModule.createLogger(winstonConfig);
  app.useLogger(appLogger);

  // Get configuration service instance for environment variables
  const configService = app.get(ConfigService);

  // Set application port (default: 3001)
  const port = configService.get<number>('APP_PORT') ?? 3001;

  // Define allowed CORS origins for security
  const allowedOrigins = [
    'https://frontend.westernoverseas.store', // Production frontend
    'http://localhost:3000', // Local development
    'http://localhost:3003',
    'http://localhost:3001', // Local api docs
    'https://westernoverseas.store', // Main domain
    'http://147.93.108.182:4001', // Local development
    'http://147.93.108.182:3001', // Local api docs
    'https://dev-vc.westernoverseas.store',
    'https://test-vc.westernoverseas.store',
  ];

  /**
   * CORS configuration for cross-origin request handling
   * This controls which domains can access the API
   */
  const corsOptions: CorsOptions = {
    origin: function (origin, callback) {
      // Allow requests with no origin (like mobile apps, curl, postman)
      if (!origin) return callback(null, true);

      // Check if the requesting origin is in the allowed list
      if (allowedOrigins.indexOf(origin) !== -1 || !origin) {
        callback(null, true); // Allow the request
      } else {
        callback(new Error('Not allowed by CORS')); // Block the request
      }
    },
    credentials: true, // Allow cookies/auth headers to be sent
    allowedHeaders: [
      'Origin',
      'X-Requested-With',
      'Content-Type',
      'Accept',
      'Authorization',
      'X-Requested-With',
      'Access-Control-Allow-Origin',
      'Access-Control-Allow-Headers',
      'Access-Control-Allow-Methods',
    ],
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH', 'HEAD'], // Allowed HTTP methods
    preflightContinue: false, // Don't pass CORS preflight to next handler
    optionsSuccessStatus: 204, // HTTP status for successful OPTIONS requests
  };

  // Enable CORS with the defined options
  app.enableCors(corsOptions);

  /**
   * Helper function to set up Swagger documentation for different module groups
   * Creates separate API documentation for different parts of the application
   *
   * @param path - URL path for the Swagger UI
   * @param description - Description shown in Swagger UI
   * @param modules - Array of modules to include in this documentation group
   */
  const setupSwagger = (path: string, description: string, modules: any[]) => {
    const config = new DocumentBuilder()
      .setTitle('Western Overseas Study Abroad Limited') // API title
      .setDescription(`API documentation for ${description}`) // API description
      .setVersion(configService.get<string>('APP_VERSION') ?? '1.0.0') // API version
      .addBearerAuth() // Add Bearer token authentication support
      .build();

    // Generate Swagger/OpenAPI documentation
    const document = SwaggerModule.createDocument(app, config, {
      include: modules, // Only include specified modules
    });

    // Setup Swagger UI at the specified path
    SwaggerModule.setup(path, app, document);
  };

  setupSwagger('api/backend/docs', 'Admin Panel', [
    GlobalModule,
    UserSettingsModule,
    UsersModule,
    DevicesModule,
    VendorsModule,
    DeviceAssignmentsModule,
    AuthorizationModule,
  ]);

  /**
   * Global validation pipe configuration
   * This automatically validates all incoming requests
   */
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true, // Automatically transform payloads to DTO instances
      whitelist: true, // Strip properties not defined in DTO
      forbidNonWhitelisted: true, // Throw error if non-whitelisted properties are present
      exceptionFactory: (validationErrors = []) => {
        /**
         * Recursively extract validation error messages from nested structures
         * Handles complex nested validation errors
         *
         * @param errors - Validation error array
         * @returns Flat array of error messages
         */
        const extractMessages = (errors: any[]): any => {
          return errors.flatMap((err) => {
            const constraints = err.constraints
              ? Object.values(err.constraints) // Get constraint messages
              : [];
            const children = err.children?.length
              ? extractMessages(err.children) // Recursively process child errors
              : [];
            return [...constraints, ...children];
          });
        };

        // Extract all validation error messages
        const messages = extractMessages(validationErrors);

        // Throw custom exception with validation errors
        return new CustomException(
          {
            message: messages.length ? messages : ['Validation failed'],
            statusCode: HttpStatus.BAD_REQUEST,
          },
          HttpStatus.BAD_REQUEST,
        );
      },
    }),
  );

  // Start the application server
  // '0.0.0.0' binds to all network interfaces (accessible from outside localhost)
  await app.listen(port, '0.0.0.0');

  // Log server startup information
  logger.log(`Application is running on: http://localhost:${port}`);

  logger.log(
    `Backend API Documentation: http://localhost:${port}/api/backend/docs`,
  );
}

// Execute the bootstrap function to start the application
bootstrap();

/**
 * Application Startup Summary:
 *
 * 1. Logging Setup:
 *    - Winston structured logging
 *    - Environment variable debugging mode
 *
 * 2. Security Configuration:
 *    - CORS with specific allowed origins
 *    - Bearer token authentication for Swagger
 *    - Input validation and sanitization
 *
 * 3. API Documentation:
 *    - Separate Swagger UI for Frontend, Backend, and Visa Commission
 *    - Organized by business domains
 *    - Versioned API documentation
 *
 * 4. Validation:
 *    - Global validation pipe with automatic DTO transformation
 *    - Whitelist protection against unwanted properties
 *    - Custom error formatting for validation failures
 *
 * 5. Server Configuration:
 *    - Configurable port (default: 3001)
 *    - Binds to all network interfaces (0.0.0.0)
 *    - Structured startup logging
 *
 * Access Points After Startup:
 * - API Base URL: http://localhost:3001
 * - Frontend Swagger: http://localhost:3001/api/frontend/docs
 * - Backend Swagger: http://localhost:3001/api/backend/docs
 * - Visa Commission Swagger: http://localhost:3001/api/visa-commission/docs
 * - Static Files: http://localhost:3001/uploads/*
 *
 * Environment Variables Used:
 * - DEBUG: Enable debug logging
 * - APP_PORT: Server port (default: 3001)
 * - APP_VERSION: API version for Swagger
 * - Various database and service configurations (loaded via ConfigModule)
 */
