import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AppModule } from './app.module';
import { LoggingInterceptor } from '@core/observability/logging/interceptors/logging.interceptor';
import { LogWriterService } from '@core/observability/logging/services/log-writer.service';
import { TraceContextService } from '@core/observability/logging/services/trace-context.service';
import { SamplingService } from '@core/observability/logging/services/sampling.service';
import { AlertService } from '@core/observability/logging/services/alert.service';
import { StructuredLoggerService } from '@core/observability/logging/services/structured-logger.service';
import { TransformInterceptor } from '@common/interceptors/transform.interceptor';
import { AllExceptionsFilter } from '@common/filters/http-exception.filter';
import { LoggerService } from '@core/observability/logging/services/logger.service';
import * as fs from 'fs';
import * as path from 'path';

// 全局 BigInt 序列化补丁（议程附件 size 字段在 Prisma 是 BigInt）。
// JSON.stringify(BigInt) 默认抛 TypeError，统一转 string 由前端 BigInt() 反序列化。
// 详见 docs/modules/meeting-attendance/03-architecture.md §BigInt 响应序列化。
if (!(BigInt.prototype as any).toJSON) {
  (BigInt.prototype as any).toJSON = function () {
    return this.toString();
  };
}

async function bootstrap() {
  // 确保 logs 目录存在
  const logsDir = path.join(process.cwd(), 'logs');
  const httpLogsDir = path.join(logsDir, 'http');
  
  if (!fs.existsSync(logsDir)) {
    fs.mkdirSync(logsDir, { recursive: true });
  }
  if (!fs.existsSync(httpLogsDir)) {
    fs.mkdirSync(httpLogsDir, { recursive: true });
  }

  // 使用自定义 Logger
  const logger = new LoggerService('Bootstrap');
  
  const app = await NestFactory.create(AppModule, {
    logger,
    bodyParser: true,
    rawBody: true,
  });
  
  const configService = app.get(ConfigService);
  const port = configService.get('port');
  const apiPrefix = configService.get('apiPrefix');
  const corsOrigins = configService.get('cors.origins');

  // 增加请求体大小限制（支持大文件导入）
  // 注意：verify 回调把原始字节挂到 req.rawBody —— **每个 JSON 请求都会多持一份
  // Buffer**（直到响应完成 + GC）。50mb 限制下单请求最差 50MB，属于已知全局副作用：
  // - webhook（Gitea HMAC / Stripe / Slack sig 等）必须有 rawBody 才能校验签名
  // - 单次最大 50mb 在我们的吞吐下风险可接受；Phase 1 若性能问题可改路由级中间件
  // 详见 .learnings/2026-05-14-express-json-overrides-nest-raw-body.md
  app.use(require('express').json({
    limit: '50mb',
    verify: (req: any, _res: unknown, buf: Buffer) => {
      req.rawBody = buf;
    },
  }));
  app.use(require('express').urlencoded({ extended: true, limit: '50mb' }));

  // cookie 解析（v2.4 Entra ID SSO 登录依赖 4 个 sso_* HttpOnly cookie）
  app.use(require('cookie-parser')());

  // 全局路由前缀
  app.setGlobalPrefix(apiPrefix);

  // 启用 CORS（添加追踪 Headers）
  app.enableCors({
    origin: process.env.NODE_ENV === 'development' 
      ? true  // 开发环境允许所有来源
      : corsOrigins,  // 生产环境使用配置的来源
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
    allowedHeaders: [
      'Content-Type',
      'Authorization',
      'Accept',
      'X-Request-Id',
      'X-Request-Time',
      'X-Requested-With',
      'X-Region-Id',
      'X-Organization-Id',
      // 分布式追踪 Headers
      'X-Trace-Id',
      'X-Span-Id',
      'X-Parent-Span-Id',
      // 管理员操作审计 Headers
      'X-Admin-Reason',
    ],
    exposedHeaders: [
      'X-Request-Id',
      'X-Trace-Id',
      'X-Span-Id',
      'X-Response-Time',
    ],
  });

  // 全局验证管道
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: false,  // 临时关闭，允许额外字段
      transform: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  );

  // 全局异常过滤器（必须在拦截器之前）
  app.useGlobalFilters(new AllExceptionsFilter());

  // 获取日志服务实例并注入到 LoggingInterceptor
  const logWriter = app.get(LogWriterService);
  const traceContextService = app.get(TraceContextService);
  const samplingService = app.get(SamplingService);
  const alertService = app.get(AlertService);
  const structuredLogger = app.get(StructuredLoggerService);

  const loggingInterceptor = new LoggingInterceptor();
  loggingInterceptor.setServices({
    logWriter,
    traceContextService,
    samplingService,
    alertService,
    structuredLogger,
  });

  // 全局拦截器
  app.useGlobalInterceptors(
    loggingInterceptor,              // 日志拦截器（完整功能）
    new TransformInterceptor(),      // 响应转换拦截器
  );

  await app.listen(port);
  
  // 启动日志
  const region = process.env.LOG_REGION || 'CN';
  const service = process.env.LOG_SERVICE || 'Backend';
  const samplingEnabled = process.env.LOG_SAMPLING_ENABLED === 'true';
  const jsonEnabled = process.env.LOG_JSON_ENABLED === 'true';

  logger.log(`🚀 Application is running on: http://localhost:${port}${apiPrefix}`);
  logger.log(`📚 API Docs: http://localhost:${port}${apiPrefix}/docs`);
  logger.log(`📝 Logging: ${process.env.LOG_LEVEL || 'info'} level`);
  logger.log(`🔍 Debug Mode: ${process.env.NODE_ENV === 'development' ? 'ON' : 'OFF'}`);
  logger.log(`📂 Log Files: ${logsDir}`);
  logger.log(`   - Application: ${path.join(logsDir, 'application-YYYY-MM-DD.log')}`);
  logger.log(`   - Errors: ${path.join(logsDir, 'error-YYYY-MM-DD.log')}`);
  logger.log(`   - HTTP: ${path.join(httpLogsDir, 'http-YYYY-MM-DD.log')}`);
  logger.log(`💾 Log Database: PostgreSQL (system_log table)`);
  logger.log(`🌍 Region: ${region} | Service: ${service}`);
  logger.log(`📊 Sampling: ${samplingEnabled ? 'ON' : 'OFF'} | JSON: ${jsonEnabled ? 'ON' : 'OFF'}`);
}

bootstrap();



