import { SetMetadata, applyDecorators } from '@nestjs/common';
import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';
import {
  IsString,
  IsNumber,
  IsBoolean,
  IsEmail,
  IsOptional,
  IsNotEmpty,
  MinLength,
  MaxLength,
  Min,
  Max,
  IsArray,
  ValidateNested,
  IsEnum,
  IsUUID,
  IsDateString,
  Matches,
  ValidationOptions,
} from 'class-validator';
import { Transform, Type } from 'class-transformer';

export const VALIDATION_GROUPS_KEY = 'validation_groups';

// Decorator para grupos de validación
export const ValidationGroups = (...groups: string[]) =>
  SetMetadata(VALIDATION_GROUPS_KEY, groups);

// Decorator combinado para validación y documentación
export function ValidateField(options: {
  type?: 'string' | 'number' | 'boolean' | 'email' | 'uuid' | 'date' | 'array';
  required?: boolean;
  minLength?: number;
  maxLength?: number;
  min?: number;
  max?: number;
  pattern?: RegExp;
  enum?: any;
  description?: string;
  example?: any;
  groups?: string[];
  transform?: (value: any) => any;
  arrayType?: any;
}) {
  const decorators: any[] = [];

  // API Documentation
  const apiOptions: ApiPropertyOptions = {
    description: options.description,
    example: options.example,
    required: options.required !== false,
  };

  if (options.enum) {
    apiOptions.enum = options.enum;
  }

  decorators.push(ApiProperty(apiOptions));

  // Validation decorators
  const validationOptions: ValidationOptions = {
    groups: options.groups,
  };

  if (!options.required) {
    decorators.push(IsOptional());
  } else {
    decorators.push(IsNotEmpty(validationOptions));
  }

  // Type-specific validations
  switch (options.type) {
    case 'string':
      decorators.push(IsString(validationOptions));
      if (options.minLength) {
        decorators.push(MinLength(options.minLength, validationOptions));
      }
      if (options.maxLength) {
        decorators.push(MaxLength(options.maxLength, validationOptions));
      }
      if (options.pattern) {
        decorators.push(Matches(options.pattern, validationOptions));
      }
      break;

    case 'number':
      decorators.push(IsNumber({}, validationOptions));
      if (options.min !== undefined) {
        decorators.push(Min(options.min, validationOptions));
      }
      if (options.max !== undefined) {
        decorators.push(Max(options.max, validationOptions));
      }
      break;

    case 'boolean':
      decorators.push(IsBoolean(validationOptions));
      break;

    case 'email':
      decorators.push(IsEmail({}, validationOptions));
      break;

    case 'uuid':
      decorators.push(IsUUID(4, validationOptions));
      break;

    case 'date':
      decorators.push(IsDateString({}, validationOptions));
      break;

    case 'array':
      decorators.push(IsArray(validationOptions));
      if (options.arrayType) {
        decorators.push(ValidateNested({ each: true, ...validationOptions }));
        decorators.push(Type(() => options.arrayType));
      }
      break;
  }

  if (options.enum) {
    decorators.push(IsEnum(options.enum, validationOptions));
  }

  // Transform decorator
  if (options.transform) {
    decorators.push(Transform(({ value }) => options.transform!(value)));
  }

  return applyDecorators(...decorators);
}

// Decorators específicos comunes
export function ValidateString(options: {
  required?: boolean;
  minLength?: number;
  maxLength?: number;
  pattern?: RegExp;
  description?: string;
  example?: string;
  groups?: string[];
} = {}) {
  return ValidateField({
    type: 'string',
    ...options,
  });
}

export function ValidateNumber(options: {
  required?: boolean;
  min?: number;
  max?: number;
  description?: string;
  example?: number;
  groups?: string[];
} = {}) {
  return ValidateField({
    type: 'number',
    ...options,
  });
}

export function ValidateEmail(options: {
  required?: boolean;
  description?: string;
  example?: string;
  groups?: string[];
} = {}) {
  return ValidateField({
    type: 'email',
    description: options.description || 'Email address',
    example: options.example || 'user@example.com',
    ...options,
  });
}

export function ValidateUUID(options: {
  required?: boolean;
  description?: string;
  example?: string;
  groups?: string[];
} = {}) {
  return ValidateField({
    type: 'uuid',
    description: options.description || 'UUID identifier',
    example: options.example || '123e4567-e89b-12d3-a456-426614174000',
    ...options,
  });
}

export function ValidateDate(options: {
  required?: boolean;
  description?: string;
  example?: string;
  groups?: string[];
} = {}) {
  return ValidateField({
    type: 'date',
    description: options.description || 'ISO date string',
    example: options.example || '2023-12-01T00:00:00.000Z',
    ...options,
  });
}

export function ValidateArray(options: {
  required?: boolean;
  arrayType?: any;
  description?: string;
  example?: any[];
  groups?: string[];
} = {}) {
  return ValidateField({
    type: 'array',
    ...options,
  });
}

export function ValidateEnum(enumObject: any, options: {
  required?: boolean;
  description?: string;
  example?: any;
  groups?: string[];
} = {}) {
  return ValidateField({
    enum: enumObject,
    description: options.description || `One of: ${Object.values(enumObject).join(', ')}`,
    ...options,
  });
}