package tool

import (
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/loveuer/upp/pkg/log"
	"golang.org/x/crypto/pbkdf2"
)

const (
	EncryptHeader string = "pbkdf2:sha256" // 用户密码加密
)

func NewPassword(password string) string {
	return EncryptPassword(password, RandomString(8), int(RandomInt(50000)+100000))
}

func ComparePassword(in, db string) bool {
	strs := strings.Split(db, "$")
	if len(strs) != 3 {
		log.Error("password in db invalid: %s", db)
		return false
	}

	encs := strings.Split(strs[0], ":")
	if len(encs) != 3 {
		log.Error("password in db invalid: %s", db)
		return false
	}

	encIteration, err := strconv.Atoi(encs[2])
	if err != nil {
		log.Error("password in db invalid: %s, convert iter err: %s", db, err)
		return false
	}

	return EncryptPassword(in, strs[1], encIteration) == db
}

func EncryptPassword(password, salt string, iter int) string {
	hash := pbkdf2.Key([]byte(password), []byte(salt), iter, 32, sha256.New)
	encrypted := hex.EncodeToString(hash)
	return fmt.Sprintf("%s:%d$%s$%s", EncryptHeader, iter, salt, encrypted)
}

func CheckPassword(password string) error {
	if len(password) < 8 || len(password) > 32 {
		return errors.New("密码长度不符合")
	}

	var (
		err          error
		match        bool
		patternList  = []string{`[0-9]+`, `[a-z]+`, `[A-Z]+`, `[!@#%]+`} //, `[~!@#$%^&*?_-]+`}
		matchAccount = 0
		tips         = []string{"缺少数字", "缺少小写字母", "缺少大写字母", "缺少'!@#%'"}
		locktips     = make([]string, 0)
	)

	for idx, pattern := range patternList {
		match, err = regexp.MatchString(pattern, password)
		if err != nil {
			log.Warn("regex match string err, reg_str: %s, err: %v", pattern, err)
			return errors.New("密码强度不够")
		}

		if match {
			matchAccount++
		} else {
			locktips = append(locktips, tips[idx])
		}
	}

	if matchAccount < 3 {
		return fmt.Errorf("密码强度不够, 可能 %s", strings.Join(locktips, ", "))
	}

	return nil
}