/**
 * Test App Helper
 * 
 * 用于创建与生产环境配置一致的测试应用
 * 但禁用审计日志以避免测试中的外键约束错误
 * 
 * 基于: src/main.ts
 * 版本: v2.1
 */

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { AppModule } from '@/app.module';
import { ConfigService } from '@nestjs/config';
import { TransformInterceptor } from '@common/interceptors/transform.interceptor';
import { AllExceptionsFilter } from '@common/filters/http-exception.filter';
import { pingTestDb, checkAndAbortIfFatal } from './db-fail-fast';

/**
 * 创建测试应用（禁用审计日志，保持其他配置与生产一致）
 */
export async function createTestApp(): Promise<INestApplication> {
  // DB 健康检查：DB 死了立刻 abort 整轮，避免每个 suite 各 18s 超时浪费 CI 时间
  await pingTestDb();

  const moduleFixture: TestingModule = await Test.createTestingModule({
    imports: [AppModule],
  })
    // 禁用审计日志拦截器以避免测试中的外键约束问题
    .overrideProvider(APP_INTERCEPTOR)
    .useValue({
      intercept: (context, next) => next.handle(), // 空拦截器
    })
    .compile();

  const app = moduleFixture.createNestApplication();
  const configService = app.get(ConfigService);

  // 设置全局前缀（与 main.ts 一致）
  const apiPrefix = configService.get('apiPrefix') || '/api/v1';
  app.setGlobalPrefix(apiPrefix);

  // 全局验证管道（与 main.ts 一致）
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: false,
      transform: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  );

  // 全局异常过滤器（与 main.ts 一致）
  app.useGlobalFilters(new AllExceptionsFilter());

  // 全局响应转换拦截器（与 main.ts 一致）
  app.useGlobalInterceptors(new TransformInterceptor());

  // 启用 CORS（测试环境）
  app.enableCors({
    origin: true,
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  });

  try {
    await app.init();
  } catch (err) {
    // app.init 中 onModuleInit 跑 prisma 时撞上 connection closed → 直接 abort 整轮
    checkAndAbortIfFatal(err, 'createTestApp app.init');
    throw err;
  }

  return app;
}

