import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import { InputSanitizer } from './input-sanitizer';

/**
 * Custom Angular Validators for Security
 */
export class SecurityValidators {
  /**
   * Validator to check for XSS attack patterns
   */
  static noXss(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      if (InputSanitizer.isMalicious(value)) {
        return { xss: { value: 'Input contains potentially dangerous content' } };
      }

      return null;
    };
  }

  /**
   * Validator to check for SQL injection patterns
   */
  static noSqlInjection(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      if (InputSanitizer.containsSqlInjection(value)) {
        return { sqlInjection: { value: 'Input contains invalid characters' } };
      }

      return null;
    };
  }

  /**
   * Secure email validator with sanitization check
   */
  static secureEmail(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      const sanitized = InputSanitizer.sanitizeEmail(value);
      if (!sanitized || sanitized !== value.trim().toLowerCase()) {
        return { secureEmail: { value: 'Invalid email format' } };
      }

      return null;
    };
  }

  /**
   * Secure phone validator
   */
  static securePhone(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      const sanitized = InputSanitizer.sanitizePhone(value);
      if (!sanitized) {
        return { securePhone: { value: 'Invalid phone number format' } };
      }

      return null;
    };
  }

  /**
   * Password strength validator
   */
  static passwordStrength(options?: {
    minLength?: number;
    requireUppercase?: boolean;
    requireLowercase?: boolean;
    requireDigit?: boolean;
    requireSpecial?: boolean;
  }): ValidatorFn {
    const opts = {
      minLength: 8,
      requireUppercase: true,
      requireLowercase: true,
      requireDigit: true,
      requireSpecial: true,
      ...options,
    };

    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      const errors: string[] = [];

      if (value.length < opts.minLength) {
        errors.push(`at least ${opts.minLength} characters`);
      }

      if (opts.requireUppercase && !/[A-Z]/.test(value)) {
        errors.push('an uppercase letter');
      }

      if (opts.requireLowercase && !/[a-z]/.test(value)) {
        errors.push('a lowercase letter');
      }

      if (opts.requireDigit && !/\d/.test(value)) {
        errors.push('a number');
      }

      if (opts.requireSpecial && !/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(value)) {
        errors.push('a special character');
      }

      if (errors.length > 0) {
        return {
          passwordStrength: {
            value: `Password must contain ${errors.join(', ')}`,
          },
        };
      }

      return null;
    };
  }

  /**
   * Alphanumeric only validator (with optional allowed characters)
   */
  static alphanumeric(allowedChars: string = ''): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      const pattern = new RegExp(
        `^[a-zA-Z0-9${allowedChars.replace(/[-]/g, '\\-')}]+$`
      );

      if (!pattern.test(value)) {
        return {
          alphanumeric: {
            value: 'Only letters, numbers' + (allowedChars ? ` and ${allowedChars}` : '') + ' are allowed',
          },
        };
      }

      return null;
    };
  }

  /**
   * Safe text validator (no HTML/script tags)
   */
  static safeText(maxLength: number = 1000): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      if (value.length > maxLength) {
        return { safeText: { value: `Maximum length is ${maxLength} characters` } };
      }

      if (/<[^>]*>/.test(value)) {
        return { safeText: { value: 'HTML tags are not allowed' } };
      }

      return null;
    };
  }

  /**
   * DigiLocker ID validator
   */
  static digilockerId(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      // DigiLocker ID format: DL-XXX-NNN or similar alphanumeric pattern
      const pattern = /^[A-Z0-9]{2,4}-[A-Z0-9]{2,10}-[A-Z0-9]{3,10}$/i;

      if (!pattern.test(value.trim())) {
        return { digilockerId: { value: 'Invalid DigiLocker ID format' } };
      }

      return null;
    };
  }

  /**
   * Department code validator
   */
  static departmentCode(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      // Department code: uppercase letters, numbers, underscores
      const pattern = /^[A-Z][A-Z0-9_]{2,29}$/;
      const upperValue = value.trim().toUpperCase();

      if (!pattern.test(upperValue)) {
        return {
          departmentCode: {
            value: 'Department code must start with a letter and contain only uppercase letters, numbers, and underscores (3-30 characters)',
          },
        };
      }

      return null;
    };
  }

  /**
   * API key validator
   */
  static apiKey(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      // API key should be alphanumeric, reasonable length
      const trimmed = value.trim();
      if (trimmed.length < 16 || trimmed.length > 256) {
        return { apiKey: { value: 'API key must be between 16 and 256 characters' } };
      }

      if (!/^[A-Za-z0-9_-]+$/.test(trimmed)) {
        return { apiKey: { value: 'API key contains invalid characters' } };
      }

      return null;
    };
  }

  /**
   * No whitespace only validator
   */
  static noWhitespaceOnly(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (!value || typeof value !== 'string') {
        return null;
      }

      if (value.trim().length === 0) {
        return { noWhitespaceOnly: { value: 'Input cannot be empty or whitespace only' } };
      }

      return null;
    };
  }
}
