import { NestFactory } from "@nestjs/core";
import { ValidationPipe } from "@nestjs/common";
import cookieParser from "cookie-parser";
import { AppModule } from "./app.module";
import { GlobalExceptionFilter } from "./filters/global-exception.filter";

function getPort(): number {
  const portEnv = process.env.PORT;

  if (portEnv === undefined || portEnv === "") {
    return 3001;
  }

  const port = parseInt(portEnv, 10);

  if (isNaN(port)) {
    throw new Error(`Invalid PORT environment variable: "${portEnv}". PORT must be a number.`);
  }

  if (port < 1 || port > 65535) {
    throw new Error(
      `Invalid PORT environment variable: ${String(port)}. PORT must be between 1 and 65535.`
    );
  }

  return port;
}

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Enable cookie parser for session handling
  app.use(cookieParser());

  // Enable global validation pipe with transformation
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true,
      whitelist: true,
      forbidNonWhitelisted: true,
      transformOptions: {
        enableImplicitConversion: false,
      },
    })
  );

  app.useGlobalFilters(new GlobalExceptionFilter());

  // Configure CORS for cookie-based authentication
  // SECURITY: Cannot use wildcard (*) with credentials: true
  const isDevelopment = process.env.NODE_ENV !== "production";

  const allowedOrigins = [
    process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000",
    "https://app.mosaicstack.dev", // Production web
    "https://api.mosaicstack.dev", // Production API
  ];

  // Development-only origins (not allowed in production)
  if (isDevelopment) {
    allowedOrigins.push("http://localhost:3001"); // API origin (dev)
  }

  app.enableCors({
    origin: (
      origin: string | undefined,
      callback: (err: Error | null, allow?: boolean) => void
    ): void => {
      // SECURITY: In production, reject requests with no Origin header.
      // In development, allow no-origin requests (Postman, curl, mobile apps).
      if (!origin) {
        if (isDevelopment) {
          callback(null, true);
        } else {
          callback(new Error("CORS: Origin header is required"));
        }
        return;
      }

      // Check if origin is in allowed list
      if (allowedOrigins.includes(origin)) {
        callback(null, true);
      } else {
        callback(new Error(`Origin ${origin} not allowed by CORS`));
      }
    },
    credentials: true, // Required for cookie-based authentication
    methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
    allowedHeaders: ["Content-Type", "Authorization", "Cookie", "X-CSRF-Token", "X-Workspace-Id"],
    exposedHeaders: ["Set-Cookie"],
    maxAge: 86400, // 24 hours - cache preflight requests
  });

  const port = getPort();
  await app.listen(port);

  console.log(`API running on http://localhost:${String(port)}`);
}

bootstrap().catch((err: unknown) => {
  const isProduction = process.env.NODE_ENV === "production";
  const errorMessage = err instanceof Error ? err.message : String(err);
  const errorStack = err instanceof Error ? err.stack : undefined;

  if (isProduction) {
    console.error(
      JSON.stringify({
        level: "error",
        message: "Failed to start application",
        error: errorMessage,
        timestamp: new Date().toISOString(),
      })
    );
  } else {
    console.error("Failed to start application:", errorMessage);
    if (errorStack) {
      console.error(errorStack);
    }
  }

  process.exit(1);
});
