package com.cameleer.server.core.security;

import java.util.ArrayList;
import java.util.List;

/**
 * Validates passwords against a configurable policy.
 * <p>
 * Rules:
 * <ul>
 *   <li>Minimum 12 characters</li>
 *   <li>Must contain at least 3 of 4 character classes: uppercase, lowercase, digit, special</li>
 *   <li>Must not match the username</li>
 * </ul>
 */
public final class PasswordPolicyValidator {

    private static final int MIN_LENGTH = 12;
    private static final int MIN_CLASSES = 3;

    private PasswordPolicyValidator() {}

    /**
     * Validates a password against the policy.
     *
     * @param password the password to validate
     * @param username the username (to reject passwords matching it)
     * @return empty list if valid, otherwise a list of violation messages
     */
    public static List<String> validate(String password, String username) {
        List<String> violations = new ArrayList<>();

        if (password == null || password.length() < MIN_LENGTH) {
            violations.add("Password must be at least " + MIN_LENGTH + " characters");
        }

        if (password != null && username != null && password.equalsIgnoreCase(username)) {
            violations.add("Password must not match the username");
        }

        if (password != null) {
            int classes = countCharacterClasses(password);
            if (classes < MIN_CLASSES) {
                violations.add("Password must contain at least " + MIN_CLASSES
                        + " of 4 character classes: uppercase, lowercase, digit, special");
            }
        }

        return violations;
    }

    private static int countCharacterClasses(String password) {
        boolean hasUpper = false;
        boolean hasLower = false;
        boolean hasDigit = false;
        boolean hasSpecial = false;

        for (int i = 0; i < password.length(); i++) {
            char c = password.charAt(i);
            if (Character.isUpperCase(c)) hasUpper = true;
            else if (Character.isLowerCase(c)) hasLower = true;
            else if (Character.isDigit(c)) hasDigit = true;
            else hasSpecial = true;
        }

        int count = 0;
        if (hasUpper) count++;
        if (hasLower) count++;
        if (hasDigit) count++;
        if (hasSpecial) count++;
        return count;
    }
}
