import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
import helmet from 'helmet';
import compression from 'compression';
import { ValidationPipe } from '@nestjs/common';
import { setupSwagger } from './swagger/swagger';
import type { Express } from 'express';
import express from 'express';
import { join } from 'path';
import { existsSync } from 'fs';

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

  const config = app.get(ConfigService);
  const expressApp = app.getHttpAdapter().getInstance() as unknown as Express;

  // Easebuzz returns form-encoded payloads to surl/furl.
  app.use(express.urlencoded({ extended: true }));

  // Vercel/clients call APIs under `/api/*`
  app.setGlobalPrefix('api');

  if (config.get<boolean>('app.trustProxy')) {
    expressApp.set('trust proxy', 1);
  }

  // Swagger UI uses inline scripts/styles; Helmet CSP can break "Try it out".
  app.use(
    helmet({
      contentSecurityPolicy: false,
      // Allow dashboard (different origin) to render uploaded images.
      crossOriginResourcePolicy: { policy: 'cross-origin' },
    }),
  );
  app.use(compression());
  // Serve uploaded assets (images) locally.
  app.use('/uploads', express.static(join(process.cwd(), 'uploads')));

  const origins = config.get<string[]>('cors.origins') ?? [];
  app.enableCors({
    origin: origins.length > 0 ? origins : true,
    credentials: config.get<boolean>('cors.credentials') ?? false,
  });

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

  setupSwagger(app, config);
  app.enableShutdownHooks();

  /**
   * Serve the Vite web build (from `../cashi_backend`) on the same origin.
   * - Web app: `/`
   * - APIs: `/api/*`
   * - Swagger: `/docs`
   * - Uploads: `/uploads/*`
   *
   * Build step should copy `cashi_backend/dist/*` into `Cashi_API/web/*`.
   */
  const webDir = join(process.cwd(), 'web');
  const webIndex = join(webDir, 'index.html');
  if (existsSync(webIndex)) {
    app.use(express.static(webDir));
    // SPA fallback (do not hijack API/docs/uploads)
    expressApp.get(
      /^\/(?!api(?:\/|$)|docs(?:\/|$)|uploads(?:\/|$)).*/,
      (req, res) => {
        res.sendFile(webIndex);
      },
    );
  }

  await app.listen(config.get<number>('app.port') ?? 3000);
}
void bootstrap();
