import { NestFactory } from '@nestjs/core';
import { ValidationPipe, Logger } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import type { NestExpressApplication } from '@nestjs/platform-express';
import helmet from 'helmet';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap(): Promise<void> {
  const logger = new Logger('Bootstrap');
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // Serve uploaded avatars as static files
  app.useStaticAssets(join(process.cwd(), '..', '..', 'data', 'avatars'), {
    prefix: '/avatars/',
  });

  // Security headers
  app.use(
    helmet({
      contentSecurityPolicy: false, // Swagger UI needs inline scripts
      crossOriginEmbedderPolicy: false,
    }),
  );

  // Global prefix for all routes
  app.setGlobalPrefix('v1');

  // CORS — restrict to known origins in production
  const corsOrigin = process.env.CORS_ORIGIN;
  app.enableCors({
    origin: corsOrigin ? corsOrigin.split(',').map((o) => o.trim()) : '*',
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
    credentials: !!corsOrigin,
  });

  // Request body size limit (NestJS API — replaces built-in parser, no duplicates)
  app.useBodyParser('json', { limit: '10mb' });
  app.useBodyParser('urlencoded', { limit: '10mb', extended: true });

  // Global validation pipe
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      transform: true,
      forbidNonWhitelisted: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  );

  // Warn if JWT secrets use defaults
  const jwtSecret = process.env.JWT_SECRET;
  const jwtRefreshSecret = process.env.JWT_REFRESH_SECRET;
  if (!jwtSecret || jwtSecret === 'change-me-in-production') {
    logger.warn('JWT_SECRET is not set or uses default value — set a strong secret in production!');
  }
  if (!jwtRefreshSecret || jwtRefreshSecret === 'change-me-refresh-in-production') {
    logger.warn(
      'JWT_REFRESH_SECRET is not set or uses default value — set a strong secret in production!',
    );
  }

  // Swagger / OpenAPI
  const swaggerConfig = new DocumentBuilder()
    .setTitle('MyFitCRM API')
    .setDescription('CRM system for fitness clubs')
    .setVersion('1.0')
    .addBearerAuth()
    .addApiKey({ type: 'apiKey', name: 'X-API-Key', in: 'header' }, 'api-key')
    .build();

  const document = SwaggerModule.createDocument(app, swaggerConfig);
  SwaggerModule.setup('api/docs', app, document);

  // Serve OpenAPI JSON spec for client generation
  const httpAdapter = app.getHttpAdapter();
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
  httpAdapter.get('/api/docs-json', (_req: any, res: any) => res.json(document));

  // Redirect root to Swagger docs
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
  httpAdapter.get('/', (_req: any, res: any) => res.redirect('/api/docs'));

  const port = process.env.API_PORT || 3000;
  await app.listen(port);

  logger.log(`MyFitCRM API is running on http://localhost:${port}`);
  logger.log(`Swagger docs available at http://localhost:${port}/api/docs`);
}

void bootstrap();
