/// 비밀번호 정책을 검증하기 위한 규칙 모음.
class PasswordRules {
  PasswordRules._();

  /// 허용 최소 길이.
  static const int minLength = 8;

  /// 허용 최대 길이.
  static const int maxLength = 24;

  static final RegExp _uppercase = RegExp(r'[A-Z]');
  static final RegExp _lowercase = RegExp(r'[a-z]');
  static final RegExp _digit = RegExp(r'[0-9]');
  static final RegExp _special = RegExp(
    "[!@#\$%\\^&*()_+\\-={}\\[\\]\\\\|:;\"'<>,.?/~`]",
  );

  /// 입력이 모든 비밀번호 규칙을 만족하는지 검사한다.
  static bool isValid(String value) => validate(value).isEmpty;

  /// 비밀번호 정책 위반 항목을 반환한다.
  static List<PasswordRuleViolation> validate(String value) {
    final violations = <PasswordRuleViolation>[];
    final length = value.length;
    if (length < minLength) {
      violations.add(PasswordRuleViolation.tooShort);
    }
    if (length > maxLength) {
      violations.add(PasswordRuleViolation.tooLong);
    }
    if (!_uppercase.hasMatch(value)) {
      violations.add(PasswordRuleViolation.missingUppercase);
    }
    if (!_lowercase.hasMatch(value)) {
      violations.add(PasswordRuleViolation.missingLowercase);
    }
    if (!_digit.hasMatch(value)) {
      violations.add(PasswordRuleViolation.missingDigit);
    }
    if (!_special.hasMatch(value)) {
      violations.add(PasswordRuleViolation.missingSpecial);
    }
    return violations;
  }
}

/// 비밀번호 규칙 위반 유형.
enum PasswordRuleViolation {
  tooShort,
  tooLong,
  missingUppercase,
  missingLowercase,
  missingDigit,
  missingSpecial,
}
