package security

import (
	"fmt"
	"unicode"
	"unicode/utf8"
)

// PasswordPolicy defines the runtime password rules enforced by services.
type PasswordPolicy struct {
	MinLength      int
	RequireSpecial bool
	RequireNumber  bool
}

// Normalize fills in safe defaults for unset policy fields.
func (p PasswordPolicy) Normalize() PasswordPolicy {
	if p.MinLength <= 0 {
		p.MinLength = 8
	}
	return p
}

// Validate checks whether the password satisfies the configured policy.
func (p PasswordPolicy) Validate(password string) error {
	p = p.Normalize()

	if utf8.RuneCountInString(password) < p.MinLength {
		return fmt.Errorf("密码长度不能少于%d位", p.MinLength)
	}

	var hasUpper, hasLower, hasNumber, hasSpecial bool
	for _, ch := range password {
		switch {
		case unicode.IsUpper(ch):
			hasUpper = true
		case unicode.IsLower(ch):
			hasLower = true
		case unicode.IsDigit(ch):
			hasNumber = true
		case unicode.IsPunct(ch) || unicode.IsSymbol(ch):
			hasSpecial = true
		}
	}

	if !hasUpper {
		return fmt.Errorf("密码必须包含大写字母")
	}
	if !hasLower {
		return fmt.Errorf("密码必须包含小写字母")
	}
	if p.RequireNumber && !hasNumber {
		return fmt.Errorf("密码必须包含数字")
	}
	if p.RequireSpecial && !hasSpecial {
		return fmt.Errorf("密码必须包含特殊字符")
	}

	return nil
}
