package cn.novalon.gym.manage.sys.primitive;

import cn.novalon.gym.manage.common.exception.ErrorCode;
import cn.novalon.gym.manage.common.exception.ValidationException;
import org.apache.commons.lang3.StringUtils;

/**
 * 密码值对象
 * 
 * @author 张翔
 * @date 2026-03-13
 */
public final class Password {

    private static final int MIN_LENGTH = 8;

    private final String value;

    public String getValue() {
        return value;
    }

    private Password(String value) {
        this.value = value;
    }

    public static Password of(String value) {
        if (StringUtils.isBlank(value)) {
            throw new ValidationException(ErrorCode.VALIDATION_REQUIRED, "Password is required");
        }
        validate(value);
        return new Password(value);
    }

    private static void validate(String value) {
        if (value.length() < MIN_LENGTH) {
            throw new ValidationException(ErrorCode.VALIDATION_INVALID_LENGTH, 
                    "Password must be at least " + MIN_LENGTH + " characters long");
        }

        boolean hasUppercase = value.chars().anyMatch(Character::isUpperCase);
        boolean hasLowercase = value.chars().anyMatch(Character::isLowerCase);
        boolean hasDigit = value.chars().anyMatch(Character::isDigit);
        boolean hasSpecial = value.chars().anyMatch(c -> !Character.isLetterOrDigit(c));

        if (!hasUppercase || !hasLowercase || !hasDigit || !hasSpecial) {
            throw new ValidationException(ErrorCode.VALIDATION_INVALID_VALUE,
                    "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character");
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Password password = (Password) o;
        return value.equals(password.value);
    }

    @Override
    public int hashCode() {
        return value.hashCode();
    }

    @Override
    public String toString() {
        return "********";
    }
}
