import "reflect-metadata"
import { NestFactory } from "@nestjs/core"
import { AppModule } from "./app.module"
import * as dotenv from "dotenv"
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"
import * as process from "node:process"
import * as express from "express"
import { ValidationPipe, VersioningType } from "@nestjs/common"
import { validationError } from "./common/response/validation-error.response"
import basicAuth from "express-basic-auth"
import { getCurrentEnvironment } from "./utils/helpers"
import { IoAdapter } from "@nestjs/platform-socket.io"

dotenv.config()

const bootstrap = async () => {
  try {
    const port = process.env.PORT || 6000
    const app = await NestFactory.create(AppModule)

    // Remove X-Powered-By on every response so the server does not leak framework info (security best practice)
    const serverInstance = app.getHttpAdapter?.().getInstance?.()
    if (serverInstance && typeof serverInstance.disable === "function") {
      serverInstance.disable("x-powered-by")
    }
    app.use(
      (
        _req: express.Request,
        res: express.Response,
        next: express.NextFunction,
      ) => {
        res.removeHeader("X-Powered-By")
        next()
      },
    )

    // Content-Security-Policy: no unsafe-inline / unsafe-eval; explicit directives only
    app.use(
      (
        _req: express.Request,
        res: express.Response,
        next: express.NextFunction,
      ) => {
        res.setHeader(
          "Content-Security-Policy",
          [
            "default-src 'self'",
            "script-src 'self'",
            "style-src 'self'",
            "img-src 'self'",
            "connect-src 'self'",
            "font-src 'self'",
            "object-src 'none'",
            "frame-src 'none'",
            "frame-ancestors 'none'",
            "base-uri 'self'",
            "form-action 'self'",
          ].join("; "),
        )
        next()
      },
    )

    app.setGlobalPrefix("api")

    // When no version is passed (e.g. /api/hospitals), treat as v1 (e.g. /api/v1/hospitals)
    app.use((req: express.Request, _res, next) => {
      const path = req.url?.split("?")[0] ?? ""
      if (path.match(/^\/api\/(?!v\d+|docs)/)) {
        req.url = req.url!.replace(/^(\/api)\/(?!v\d+|docs)/, "$1/v1/")
      }
      next()
    })

    // Enable API versioning with URL-based versioning (e.g., /api/v1/hospitals)
    app.enableVersioning({
      type: VersioningType.URI,
      defaultVersion: "1", // Default version if not specified
    })

    app.use(express.static("public"))
    app.enableCors()
    app.useWebSocketAdapter(new IoAdapter(app))

    if (process.env.NODE_ENV != "production") {
      // Basic Auth middleware
      const swaggerAdmin = process.env.SWAGGER_USERNAME
      const swaggerPassword = process.env.SWAGGER_PASSWORD

      getCurrentEnvironment() != "local" &&
        app.use(
          "/api/docs",
          basicAuth({
            users: { [swaggerAdmin]: swaggerPassword }, // Replace with your credentials
            challenge: true,
            realm: "Swagger API",
            unauthorizedResponse:
              "Access denied. Kindly get in touch with the developer.",
          }),
        )
      const config = new DocumentBuilder()
        .setTitle("Nuskin API Documentation")
        .setDescription("API Documentation for Nuskin")
        .setVersion("1.0")
        // .setContact("Devendra Mali", "", "devendra@moweb.com")
        .addBearerAuth(
          {
            type: "apiKey",
            in: "header",
            name: "Authorization",
            description:
              "Enter your custom token in the format `Token <your_token>`",
          },
          "access-token",
        )
        .build()

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

    // Global validation pipe
    app.useGlobalPipes(
      new ValidationPipe({
        exceptionFactory: validationError,
        transform: true, // Automatically transform payload to DTO class
        transformOptions: {
          enableImplicitConversion: true,
        },
        whitelist: true, // Strip properties that do not have decorators
      }),
    )

    // Serve public folder

    await app.listen(port)

    // if (process.env.ENABLE_CONSOLE != "true") {
    //   console.log = () => {}
    // }

    console.log(`server is running at http://localhost:${port}`)
    console.log(`Swagger is running at http://localhost:${port}/api/docs`)
  } catch (error) {
    console.log("error================", error)
  }
}
bootstrap()
