import { type INestApplication } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { NestFactory } from "@nestjs/core";
import { Logger } from "nestjs-pino";
import helmet from "helmet";
import cookieParser from "cookie-parser";
import * as express from "express";
import type { CookieOptions, Response, NextFunction, Request } from "express";

/* eslint-disable @typescript-eslint/no-namespace */
declare global {
  namespace Express {
    interface Response {
      setSecureCookie: (name: string, value: string, options?: CookieOptions) => void;
    }
  }
}
/* eslint-enable @typescript-eslint/no-namespace */

import { GlobalExceptionFilter } from "../core/http/http-exception.filter";
import { AuthErrorFilter } from "../core/http/auth-error.filter";
import { SecureErrorMapperService } from "../core/security/services/secure-error-mapper.service";

import { AppModule } from "../app.module";

export async function bootstrap(): Promise<INestApplication> {
  const app = await NestFactory.create(AppModule, {
    bufferLogs: true,
    // bodyParser is enabled by default in NestJS
    rawBody: true, // Enable raw body access for debugging
  });

  // Set Pino as the logger
  app.useLogger(app.get(Logger));

  const configService = app.get(ConfigService);
  const logger = app.get(Logger);

  // Enhanced Security Headers
  app.use(
    helmet({
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
          scriptSrc: ["'self'"],
          imgSrc: ["'self'", "data:", "https:"],
          connectSrc: ["'self'"],
          fontSrc: ["'self'"],
          objectSrc: ["'none'"],
          mediaSrc: ["'self'"],
          frameSrc: ["'none'"],
        },
      },
      crossOriginEmbedderPolicy: false,
      crossOriginResourcePolicy: { policy: "cross-origin" },
    })
  );

  // Disable x-powered-by header
  const expressInstance = app.getHttpAdapter().getInstance() as {
    disable?: (name: string) => void;
  };
  if (typeof expressInstance?.disable === "function") {
    expressInstance.disable("x-powered-by");
  }

  // Configure JSON body parser with proper limits
  app.use(express.json({ limit: "10mb" }));
  app.use(express.urlencoded({ extended: true, limit: "10mb" }));

  // Enhanced cookie parser with security options
  app.use(cookieParser());

  // Provide helper for secure cookie handling without mutating Express response methods
  const secureCookieDefaults: CookieOptions = {
    httpOnly: true,
    sameSite: "strict",
    secure: configService.get("NODE_ENV") === "production",
  };

  app.use((_req: Request, res: Response, next: NextFunction) => {
    res.setSecureCookie = (name: string, value: string, options: CookieOptions = {}) => {
      res.cookie(name, value, { ...secureCookieDefaults, ...options });
    };
    next();
  });

  // Trust proxy configuration for reverse proxies
  if (configService.get("TRUST_PROXY", "false") === "true") {
    const httpAdapter = app.getHttpAdapter();
    const instance = httpAdapter.getInstance() as {
      set?: (key: string, value: unknown) => void;
    };
    if (typeof instance?.set === "function") {
      instance.set("trust proxy", 1);
    }
  }

  // Enhanced CORS configuration
  const corsOrigin = configService.get<string | undefined>("CORS_ORIGIN");
  app.enableCors({
    origin: corsOrigin ? [corsOrigin] : false,
    credentials: true,
    methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
    allowedHeaders: [
      "Origin",
      "X-Requested-With",
      "Content-Type",
      "Accept",
      "Authorization",
      "X-API-Key",
      "X-CSRF-Token",
    ],
    exposedHeaders: ["X-Total-Count", "X-Page-Count"],
    maxAge: 86400, // 24 hours
  });

  // Global exception filters
  app.useGlobalFilters(
    new AuthErrorFilter(app.get(Logger)), // Handle auth errors first
    new GlobalExceptionFilter(app.get(Logger), app.get(SecureErrorMapperService)) // Handle all other errors
  );

  // Global authentication guard will be registered via APP_GUARD provider in AuthModule

  // Rely on Nest's built-in shutdown hooks. External orchestrator will send signals.
  app.enableShutdownHooks();

  // API routing prefix is applied via RouterModule in AppModule for clarity and modern routing.

  const port = Number(configService.get("BFF_PORT", 4000));

  await app.listen(port, "0.0.0.0");

  // Enhanced startup information
  logger.log(`🚀 BFF API running on: http://localhost:${port}/api`);
  logger.log(`🌐 Frontend Portal: http://localhost:${configService.get("NEXT_PORT", 3000)}`);
  if (configService.get("DATABASE_URL")) {
    logger.log("🗄️ Database connection configured");
  }
  logger.log(`🔗 Prisma Studio: http://localhost:5555`);
  if (configService.get("REDIS_URL")) {
    logger.log("🔴 Redis connection configured");
  }

  return app;
}
