import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

/**
 * Mirrors the ASP.NET Identity password policy enforced on the server:
 * at least 8 characters with an uppercase, a lowercase, a digit, and a
 * non-alphanumeric character. Client-side only — the server stays authoritative.
 * Returns null for an empty value so the `required` validator owns emptiness.
 */
export function passwordStrengthValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const value = control.value as string;
    if (!value) {
      return null;
    }

    const errors: ValidationErrors = {};
    if (value.length < 8) {
      errors['minlength'] = true;
    }
    if (!/[A-Z]/.test(value)) {
      errors['uppercase'] = true;
    }
    if (!/[a-z]/.test(value)) {
      errors['lowercase'] = true;
    }
    if (!/[0-9]/.test(value)) {
      errors['digit'] = true;
    }
    if (!/[^a-zA-Z0-9]/.test(value)) {
      errors['special'] = true;
    }

    return Object.keys(errors).length ? { passwordStrength: errors } : null;
  };
}

/**
 * Group-level validator: the confirm field must match the new password, and the
 * new password must differ from the current one.
 */
export function passwordMatchValidator(): ValidatorFn {
  return (group: AbstractControl): ValidationErrors | null => {
    const current = group.get('currentPassword')?.value;
    const next = group.get('newPassword')?.value;
    const confirm = group.get('confirmPassword')?.value;

    const errors: ValidationErrors = {};
    if (next && confirm && next !== confirm) {
      errors['mismatch'] = true;
    }
    if (next && current && next === current) {
      errors['sameAsCurrent'] = true;
    }

    return Object.keys(errors).length ? errors : null;
  };
}
