import { ValidationPipe } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { NestExpressApplication } from "@nestjs/platform-express";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import * as express from "express";
import { existsSync, mkdirSync } from "fs";
import { join } from "path";
import { AppModule } from "./app.module";
import { runPreflightChecks } from "./preflight";

async function bootstrap() {
  // ANTES de NestFactory.create(): si algo obligatorio falta, morir aca con
  // un mensaje de operador, no con el stack trace de Nest tratando de armar
  // ControlPlaneModule sin las variables que necesita.
  await runPreflightChecks();

  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // Sin esto, Express usa su default (100kb para JSON/urlencoded) sin que
  // quede documentado en ningun lado del codigo -- cualquier body de JSON
  // mas grande (ej. un data-URL embebido a mano en vez de subirse por
  // /uploads) tira "request entity too large" antes de que la app vea el
  // request. Las subidas reales de archivos (fotos, firmas, PDFs) van por
  // Multer/FileInterceptor con su propio limite de 15MB (ver
  // uploads.controller.ts) -- esto es aparte, para el body JSON normal.
  app.useBodyParser("json", { limit: "20mb" });
  app.useBodyParser("urlencoded", { limit: "20mb", extended: true });

  app.setGlobalPrefix("api/v1");
  app.use(
    (
      req: express.Request,
      res: express.Response,
      next: express.NextFunction,
    ) => {
      res.setHeader("X-Content-Type-Options", "nosniff");
      res.setHeader("X-Frame-Options", "DENY");
      res.setHeader("Referrer-Policy", "no-referrer");
      res.setHeader(
        "Permissions-Policy",
        "camera=(), microphone=(), geolocation=()",
      );
      if (req.path?.startsWith("/api/")) {
        res.setHeader("Cache-Control", "no-store");
      }
      next();
    },
  );

  const uploadDir = process.env.UPLOAD_DIR || join(process.cwd(), "uploads");
  if (!existsSync(uploadDir)) {
    mkdirSync(uploadDir, { recursive: true });
  }
  app.use("/uploads", express.static(uploadDir));

  const corsOrigins = (
    process.env.CORS_ORIGINS ||
    "http://localhost:4000,http://127.0.0.1:4000,http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001"
  )
    .split(",")
    .map((origin) => origin.trim())
    .filter(Boolean);

  app.enableCors({
    origin: corsOrigins,
    credentials: true,
  });

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

  if (
    process.env.NODE_ENV !== "production" ||
    process.env.ENABLE_SWAGGER === "true"
  ) {
    const config = new DocumentBuilder()
      .setTitle("MBTaller")
      .setDescription(
        "API para gestion de ordenes de trabajo, clientes, vehiculos y cotizaciones",
      )
      .setVersion("1.0")
      .addBearerAuth()
      .addTag("auth", "Autenticacion")
      .addTag("clientes", "Gestion de clientes")
      .addTag("vehiculos", "Maestro de vehiculos")
      .addTag("ots", "Ordenes de trabajo")
      .addTag("cotizaciones", "Cotizaciones")
      .addTag("productos", "Productos/Servicios (maeplu)")
      .addTag("catalogos", "Catalogos internos")
      .addTag("uploads", "Subida de archivos")
      .addTag("sync", "Sincronizacion offline")
      .build();

    const document = SwaggerModule.createDocument(app, config);
    SwaggerModule.setup("api/docs", app, document);
  }

  const port = process.env.PORT || 3001;
  await app.listen(port, "0.0.0.0");
  console.log(`Application running on: http://localhost:${port}/api/v1`);
  if (
    process.env.NODE_ENV !== "production" ||
    process.env.ENABLE_SWAGGER === "true"
  ) {
    console.log(`Swagger docs: http://localhost:${port}/api/docs`);
  }
}

bootstrap();
