require("dotenv").config(); // eslint-disable-line
import { ValidationPipe, VersioningType } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import {
  ExpressAdapter,
  NestExpressApplication,
} from "@nestjs/platform-express";
import helmet from "helmet";
import rateLimit from "express-rate-limit";
import * as compression from "compression";
import * as morgan from "morgan";
import { middleware as expressCtx } from "express-ctx";
import * as requestIp from "request-ip";
import { AppModule } from "./app.module";
import { setupSwagger } from "./setup-swagger";
import { TransformationInterceptor } from "./interceptors/transform.interceptor";
import { ExceptionInterceptor } from "./interceptors/exception.interceptor";
import { NotFoundInterceptor } from "./interceptors/not-found.interceptor";
import { useContainer } from "class-validator";
import * as bodyParser from 'body-parser';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(
    AppModule,
    new ExpressAdapter(),
    {
      cors: {
        origin: "*", // TODO: need specific domains
      },
    }
  );

  // Microservice
  // app.connectMicroservice(grpcUserOptions);
  // await app.startAllMicroservices();

  // security and config
  app.use(helmet());
  app.use(helmet.crossOriginResourcePolicy({ policy: "cross-origin" }));
  app.use(
    rateLimit({
      windowMs: Number(process.env.RATE_LIMIT_WINDOW_MS),
      max: Number(process.env.RATE_LIMIT_MAX),
    })
  );
  app.use(compression()); // gzip
  app.use(morgan("combined")); // format logs
  app.use(requestIp.mw());

  // prefix: /api/v1
  app.setGlobalPrefix("/api");
  app.enableVersioning({
    type: VersioningType.URI,
    defaultVersion: "1",
  });

  // whitelist — removes any property of query, body, and a parameter that is not part of our DTO
  // transform — enables the transformation of our incoming request
  app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
  app.useGlobalInterceptors(new TransformationInterceptor()); // JSON response standarization

  if (process.env.ENABLE_DOCUMENTATION == "1") {
    setupSwagger(app);
  }

  app.use(bodyParser.json({limit: '50mb'}));
  app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));

  // express-ctx: can use setValue/getValue
  app.use(expressCtx);

  await app.listen(process.env.PORT || 3000);
  console.log(`Application is running on: ${await app.getUrl()}`);

  // enable custom validator
  useContainer(app.select(AppModule), { fallbackOnErrors: true });
}
bootstrap();
