package utils

import (
	"errors"
	"regexp"
	"unicode"

	"golang.org/x/crypto/bcrypt"
)

var (
	ErrPasswordTooShort      = errors.New("密码长度至少为8个字符")
	ErrPasswordNoUpper       = errors.New("密码必须包含至少一个大写字母")
	ErrPasswordNoLower       = errors.New("密码必须包含至少一个小写字母")
	ErrPasswordNoDigit       = errors.New("密码必须包含至少一个数字")
	ErrPasswordNoSpecial     = errors.New("密码必须包含至少一个特殊字符")
	ErrPasswordCommon        = errors.New("密码不能是常见弱密码")
	ErrPasswordSameChars     = errors.New("密码不能全部是相同字符")
)

// 常见弱密码列表
var commonPasswords = []string{
	"password", "12345678", "123456789", "1234567890",
	"qwerty", "abc123", "password123", "admin123",
	"123456", "1234567", "12345", "1234",
	"admin", "root", "user", "test",
}

// ValidatePasswordStrength 验证密码强度
func ValidatePasswordStrength(password string) error {
	// 检查长度
	if len(password) < 8 {
		return ErrPasswordTooShort
	}

	// 检查是否全部相同字符
	allSame := true
	for i := 1; i < len(password); i++ {
		if password[i] != password[0] {
			allSame = false
			break
		}
	}
	if allSame {
		return ErrPasswordSameChars
	}

	// 检查是否包含大写字母
	hasUpper := false
	// 检查是否包含小写字母
	hasLower := false
	// 检查是否包含数字
	hasDigit := false
	// 检查是否包含特殊字符
	hasSpecial := false

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

	if !hasUpper {
		return ErrPasswordNoUpper
	}
	if !hasLower {
		return ErrPasswordNoLower
	}
	if !hasDigit {
		return ErrPasswordNoDigit
	}
	if !hasSpecial {
		return ErrPasswordNoSpecial
	}

	// 检查是否是常见弱密码
	lowerPassword := regexp.MustCompile(`[^a-z]`).ReplaceAllString(password, "")
	for _, common := range commonPasswords {
		if lowerPassword == common {
			return ErrPasswordCommon
		}
	}

	return nil
}

// HashPassword 加密密码
func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	return string(bytes), err
}

// CheckPassword 验证密码
func CheckPassword(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}
