import {
  Injectable,
  PipeTransform,
  ArgumentMetadata,
  BadRequestException,
} from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';

@Injectable()
export class StrictValidationPipe implements PipeTransform<any> {
  private readonly maxStringLength = 5000;

  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToInstance(metatype, value, { enableImplicitConversion: true });
    const errors = await validate(object, {
      whitelist: true,
      forbidNonWhitelisted: true,
    });
    if (errors.length > 0) {
      const messages = errors.map((err) =>
        Object.values(err.constraints || {}).join(', '),
      );
      throw new BadRequestException(messages);
    }
    this.validateStringLengths(object);
    return object;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }

  private validateStringLengths(obj: any) {
    for (const key of Object.keys(obj)) {
      if (typeof obj[key] === 'string' && obj[key].length > this.maxStringLength) {
        throw new BadRequestException(
          `字段 ${key} 长度不能超过 ${this.maxStringLength} 字符`,
        );
      }
    }
  }
}
