import { NestFactory } from '@nestjs/core';
import { VersioningType } from '@nestjs/common';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ConfigService } from '@nestjs/config';
import { I18nService, I18nValidationExceptionFilter, I18nValidationPipe } from 'nestjs-i18n';
import helmet from 'helmet';
import compression from 'compression';
import { AppModule } from './app.module';
import { Logger } from 'nestjs-pino';
import { helmetConfig, corsConfig } from './infrastructure/security/security.config';
import { DomainExceptionFilter } from './application/filters/domain-exception.filter';
import type { Request, Response, NextFunction } from 'express';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    bufferLogs: true,
    // Enable rawBody for Stripe webhooks signature verification
    rawBody: true,
  });

  // Get config service
  const configService = app.get(ConfigService);
  const port = configService.get<number>('PORT', 4000);
  const apiPrefix = configService.get<string>('API_PREFIX', 'api/v1');
  const isProduction = configService.get<string>('NODE_ENV') === 'production';

  // Use Pino logger
  app.useLogger(app.get(Logger));

  // Security - Helmet with OWASP recommended headers
  app.use(helmet(helmetConfig));

  // Compression for API responses
  app.use(compression());

  // CORS with strict configuration
  app.enableCors(corsConfig);

  // Global prefix
  app.setGlobalPrefix(apiPrefix);

  // API versioning
  app.enableVersioning({
    type: VersioningType.URI,
  });

  // Global validation pipe — i18n-aware (messages translated to caller locale)
  app.useGlobalPipes(
    new I18nValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    })
  );

  // Global exception filters — each filter declares its target via @Catch(),
  // so they don't overlap: DomainExceptionFilter handles DomainException,
  // I18nValidationExceptionFilter handles class-validator errors.
  const i18nService = app.get(I18nService) as I18nService<Record<string, unknown>>;
  app.useGlobalFilters(
    new DomainExceptionFilter(i18nService),
    new I18nValidationExceptionFilter({ detailedErrors: false })
  );

  // ─── Swagger documentation ────────────────────────────────────────────────
  const swaggerUser = configService.get<string>('SWAGGER_USERNAME');
  const swaggerPass = configService.get<string>('SWAGGER_PASSWORD');
  const swaggerEnabled = !isProduction || (Boolean(swaggerUser) && Boolean(swaggerPass));

  if (swaggerEnabled) {
    // HTTP Basic Auth guard for Swagger routes when credentials are configured
    if (swaggerUser && swaggerPass) {
      const swaggerPaths = ['/api/docs', '/api/docs-json', '/api/docs-yaml'];
      app.use(swaggerPaths, (req: Request, res: Response, next: NextFunction) => {
        const authHeader = req.headers['authorization'];
        if (!authHeader || !authHeader.startsWith('Basic ')) {
          res.setHeader('WWW-Authenticate', 'Basic realm="Xpeditis API Docs"');
          res.status(401).send('Authentication required');
          return;
        }
        const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');
        const colonIndex = decoded.indexOf(':');
        const user = decoded.slice(0, colonIndex);
        const pass = decoded.slice(colonIndex + 1);
        if (user !== swaggerUser || pass !== swaggerPass) {
          res.setHeader('WWW-Authenticate', 'Basic realm="Xpeditis API Docs"');
          res.status(401).send('Invalid credentials');
          return;
        }
        next();
      });
    }

    const config = new DocumentBuilder()
      .setTitle('Xpeditis API')
      .setDescription(
        'Maritime Freight Booking Platform - API for searching rates and managing bookings'
      )
      .setVersion('1.0')
      .addBearerAuth()
      .addApiKey({ type: 'apiKey', name: 'x-api-key', in: 'header' }, 'x-api-key')
      .addTag('rates', 'Rate search and comparison')
      .addTag('bookings', 'Booking management')
      .addTag('auth', 'Authentication and authorization')
      .addTag('users', 'User management')
      .addTag('organizations', 'Organization management')
      .build();

    const document = SwaggerModule.createDocument(app, config);
    SwaggerModule.setup('api/docs', app, document, {
      customSiteTitle: 'Xpeditis API Documentation',
      customfavIcon: 'https://xpeditis.com/favicon.ico',
      customCss: '.swagger-ui .topbar { display: none }',
    });
  }
  // ─────────────────────────────────────────────────────────────────────────

  await app.listen(port);

  const swaggerStatus = swaggerEnabled
    ? swaggerUser
      ? `http://localhost:${port}/api/docs (protected)`
      : `http://localhost:${port}/api/docs (open — add SWAGGER_USERNAME/PASSWORD to secure)`
    : 'disabled in production';

  console.log(`
    ╔═══════════════════════════════════════════════╗
    ║                                               ║
    ║   🚢 Xpeditis API Server Running             ║
    ║                                               ║
    ║   API:   http://localhost:${port}/${apiPrefix}          ║
    ║   Docs:  ${swaggerStatus}   ║
    ║                                               ║
    ╚═══════════════════════════════════════════════╝
  `);
}

bootstrap();
