import { NestFactory } from '@nestjs/core';
import { Logger, ValidationPipe } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { ConfigService } from '@nestjs/config';
import helmet from 'helmet';
import * as path from 'path';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './common/filters/all-exceptions.filter';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule, {
    bodyParser: true,
  });
  const config = app.get(ConfigService);
  const logger = new Logger('Bootstrap');

  app.set('trust proxy', 1);

  app.use(
    helmet({
      // Uploaded media is served from this origin and embedded by the admin panel.
      crossOriginResourcePolicy: { policy: 'cross-origin' },
    }),
  );

  const origins = (process.env.CORS_ORIGIN || 'http://localhost:5173')
    .split(',')
    .map((origin) => origin.trim())
    .filter(Boolean);

  app.enableCors({
    // The Flutter app sends no cookies and no Origin header, so a null origin is allowed.
    origin: (origin, callback) => {
      if (!origin || origins.includes('*') || origins.includes(origin)) {
        return callback(null, true);
      }
      return callback(new Error(`Origin ${origin} is not allowed by CORS`), false);
    },
    credentials: true,
  });

  // Drawing payloads are vector JSON and can be large; everything else is small.
  const bodyLimit = process.env.REQUEST_BODY_LIMIT || '10mb';
  app.useBodyParser('json', { limit: bodyLimit });
  app.useBodyParser('urlencoded', { limit: bodyLimit, extended: true });

  app.useStaticAssets(path.join(process.cwd(), 'uploads'), { prefix: '/uploads' });

  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
      transformOptions: { enableImplicitConversion: false },
    }),
  );

  app.useGlobalFilters(new AllExceptionsFilter());

  const port = config.get<number>('PORT') || 3000;
  app.enableShutdownHooks();
  await app.listen(port);

  logger.log(`M-TEER API listening on http://localhost:${port}`);
  logger.log(`Public content API:  /api/v1/public`);
  logger.log(`Admin API:           /api/v1/admin`);
}

bootstrap();
