import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
  BadRequestException,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';

interface FormDataValidatedOptions {
  dto: any;
  fileField?: string;
  fileTypes?: string[];
  maxSize?: number;
  fileRequired?: boolean;
}

@Injectable()
export class FormDataValidatorInterceptor implements NestInterceptor {
  constructor(private options: FormDataValidatedOptions) {}

  async intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Promise<Observable<any>> {
    const request = context.switchToHttp().getRequest();
    const body = request.body;
    const file = request.file;

    // Validate DTO
    const dtoObject = plainToInstance(this.options.dto, body);
    const errors = await validate(dtoObject);
    if (errors.length > 0) {
      throw new BadRequestException(errors);
    }

    // Validate file nếu có
    const {
      fileField = 'avatar',
      fileTypes = ['image/jpeg', 'image/png'],
      maxSize = 2 * 1024 * 1024,
      fileRequired = false,
    } = this.options;

    if (fileRequired && !file) {
      throw new BadRequestException({
        message: `${fileField} is required`,
        status_code: 400,
        errors: 'Bad Request',
        data: null,
        timestamp: new Date().toISOString(),
      });
    }

    if (file) {
      if (!fileTypes.includes(file.mimetype)) {
        throw new BadRequestException({
          message: `${fileField} must be one of: ${fileTypes.join(', ')}`,
          status_code: 400,
          errors: 'Bad Request',
          data: null,
          timestamp: new Date().toISOString(),
        });
      }

      if (file.size > maxSize) {
        throw new BadRequestException({
          message: `${fileField} size must be <= ${Math.floor(maxSize / 1024 / 1024)}MB`,
          status_code: 400,
          errors: 'Bad Request',
          data: null,
          timestamp: new Date().toISOString(),
        });
      }
    }

    return next.handle();
  }
}
