import 'dotenv/config';
import { BadRequestException, ValidationPipe } from '@nestjs/common';
import type { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { AppModule } from '../../../src/app.module.js';
import { WechatMiniAppService } from '../../../src/auth/wechat-miniapp/wechat-miniapp.service.js';
import { HttpExceptionFilter } from '../../../src/common/http-exception.filter.js';
import { MESSAGES } from '../../../src/common/messages.js';
import { ResponseEnvelopeInterceptor } from '../../../src/common/response-envelope.interceptor.js';

class FakeWechatMiniAppService {
  async resolvePhoneIdentity(loginCode: string, phoneCode: string) {
    return {
      openId: this.exchangeLoginCode(loginCode),
      phone: this.exchangePhoneCode(phoneCode),
    };
  }

  exchangeLoginCode(loginCode: string) {
    return this.parseCode(loginCode, 'mock-login:');
  }

  exchangePhoneCode(phoneCode: string) {
    return this.parseCode(phoneCode, 'mock-phone:');
  }

  private parseCode(value: string, prefix: string) {
    if (typeof value !== 'string' || !value.startsWith(prefix)) {
      throw new Error(`invalid mock miniapp code: ${value}`);
    }

    return decodeURIComponent(value.slice(prefix.length));
  }
}

export async function createE2eApp(): Promise<INestApplication> {
  const moduleRef = await Test.createTestingModule({
    imports: [AppModule],
  })
    .overrideProvider(WechatMiniAppService)
    .useValue(new FakeWechatMiniAppService())
    .compile();

  const app = moduleRef.createNestApplication();

  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      transform: true,
      forbidNonWhitelisted: true,
      exceptionFactory: (errors) => {
        const messages = errors
          .flatMap((error) => Object.values(error.constraints ?? {}))
          .filter((item): item is string => Boolean(item));

        return new BadRequestException(
          messages.length > 0
            ? messages.join('；')
            : MESSAGES.DEFAULT_BAD_REQUEST,
        );
      },
    }),
  );

  app.useGlobalFilters(new HttpExceptionFilter());
  app.useGlobalInterceptors(new ResponseEnvelopeInterceptor());

  await app.init();
  return app;
}
