package password

import (
	"regexp"
	"unicode"
)

const (
	// MinPasswordLength is the minimum required password length
	MinPasswordLength = 8
	// MaxPasswordLength is the maximum allowed password length
	MaxPasswordLength = 128
)

var (
	// Special characters allowed in passwords
	specialCharRegex = regexp.MustCompile(`[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]`)
)

// PasswordValidator provides password strength validation
type PasswordValidator interface {
	ValidatePasswordStrength(password string) error
}

type passwordValidator struct{}

// NewPasswordValidator creates a new password validator
func NewPasswordValidator() PasswordValidator {
	return &passwordValidator{}
}

// ValidatePasswordStrength validates that a password meets strength requirements
// Requirements:
// - At least 8 characters long
// - At most 128 characters long
// - Contains at least one uppercase letter
// - Contains at least one lowercase letter
// - Contains at least one digit
// - Contains at least one special character
//
// CWE-521: Returns granular error messages to help users create strong passwords
func (v *passwordValidator) ValidatePasswordStrength(password string) error {
	// Check length first
	if len(password) < MinPasswordLength {
		return ErrPasswordTooShort
	}

	if len(password) > MaxPasswordLength {
		return ErrPasswordTooLong
	}

	// Check character type requirements
	var (
		hasUpper   bool
		hasLower   bool
		hasNumber  bool
		hasSpecial bool
	)

	for _, char := range password {
		switch {
		case unicode.IsUpper(char):
			hasUpper = true
		case unicode.IsLower(char):
			hasLower = true
		case unicode.IsNumber(char):
			hasNumber = true
		}
	}

	// Check for special characters
	hasSpecial = specialCharRegex.MatchString(password)

	// Return granular error for the first missing requirement
	// This provides specific feedback to users about what's missing
	if !hasUpper {
		return ErrPasswordNoUppercase
	}
	if !hasLower {
		return ErrPasswordNoLowercase
	}
	if !hasNumber {
		return ErrPasswordNoNumber
	}
	if !hasSpecial {
		return ErrPasswordNoSpecialChar
	}

	return nil
}
