import 'reflect-metadata';
import cookie from '@fastify/cookie';
import helmet from '@fastify/helmet';
import rateLimit from '@fastify/rate-limit';
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, type NestFastifyApplication } from '@nestjs/platform-fastify';
import { Logger } from 'nestjs-pino';
import { AppModule } from './app.module';
import { ApiExceptionFilter } from './common/http/api-exception.filter';

async function bootstrap(): Promise<void> {
  const adapter = new FastifyAdapter({
    trustProxy: true,
    bodyLimit: 1_048_576,
  });
  const app = await NestFactory.create<NestFastifyApplication>(AppModule, adapter, {
    bufferLogs: true,
  });

  const config = app.get(ConfigService);
  app.useLogger(app.get(Logger));
  app.enableShutdownHooks();
  app.setGlobalPrefix('api/v1');
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
      stopAtFirstError: false,
    }),
  );
  app.useGlobalFilters(new ApiExceptionFilter());

  await app.register(cookie);
  await app.register(helmet, {
    contentSecurityPolicy: false,
  });
  await app.register(rateLimit, {
    max: config.get<number>('RATE_LIMIT_MAX', 200),
    timeWindow: config.get<number>('RATE_LIMIT_WINDOW_MS', 60_000),
  });

  const allowedOrigins = config
    .getOrThrow<string>('APP_ORIGIN')
    .split(',')
    .map((origin) => origin.trim());
  app.enableCors({
    origin: allowedOrigins,
    credentials: true,
    methods: ['GET', 'HEAD', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],
  });

  if (config.get<boolean>('SWAGGER_ENABLED', false)) {
    const { DocumentBuilder, SwaggerModule } = await import('@nestjs/swagger');
    const documentConfig = new DocumentBuilder()
      .setTitle('CK Terminal API')
      .setDescription('Authenticated API for CK Trading, Portfolio and Market Data.')
      .setVersion('1.0')
      .addCookieAuth(config.get<string>('SESSION_COOKIE_NAME', 'ck_session'))
      .build();
    const document = SwaggerModule.createDocument(app, documentConfig);
    SwaggerModule.setup('api/docs', app, document, {
      jsonDocumentUrl: 'api/docs/openapi.json',
    });
  }

  await app.listen(config.get<number>('PORT', 4000), config.get<string>('HOST', '127.0.0.1'));
}

void bootstrap();
