package service

import (
	"fmt"
	"time"

	"be.ems/src/framework/config"
	"be.ems/src/framework/constants"
	"be.ems/src/framework/database/redis"
	"be.ems/src/framework/token"
	"be.ems/src/framework/utils/crypto"
	"be.ems/src/framework/utils/parse"
)

// ValidateCaptcha 校验验证码
func (s Account) ValidateCaptcha(code, uuid string) error {
	// 验证码检查，从数据库配置获取验证码开关 true开启，false关闭
	captchaEnabledStr := s.sysConfigService.FindValueByKey("sys.account.captchaEnabled")
	if !parse.Boolean(captchaEnabledStr) {
		return nil
	}
	if code == "" || uuid == "" {
		// 验证码信息错误
		return fmt.Errorf("captcha.err")
	}
	verifyKey := constants.CACHE_CAPTCHA_CODE + ":" + uuid
	captcha, _ := redis.Get("", verifyKey)
	if captcha == "" {
		// 验证码已失效
		return fmt.Errorf("captcha.errValid")
	}
	_ = redis.Del("", verifyKey)
	if captcha != code {
		// 验证码错误
		return fmt.Errorf("captcha.err")
	}
	return nil
}

// ByUsername 登录创建用户信息
func (s Account) ByUsername(username, password string) (token.UserInfo, error) {
	info := token.UserInfo{}

	// 检查密码重试次数
	retryKey, retryCount, lockTime, err := s.passwordRetryCount(username)
	if err != nil {
		return info, err
	}

	// 查询用户登录账号
	sysUser := s.sysUserService.FindByUserName(username, "System", "#")
	if sysUser.UserName != username {
		return info, fmt.Errorf("login.errNameOrPasswd")
	}
	if sysUser.DelFlag == constants.STATUS_YES {
		return info, fmt.Errorf("login.errDelFlag")
	}
	if sysUser.StatusFlag == constants.STATUS_NO {
		return info, fmt.Errorf("login.errStatus")
	}

	// 检验用户密码
	compareBool := crypto.BcryptCompare(password, sysUser.Password)
	if compareBool {
		s.CleanLoginRecordCache(sysUser.UserName) // 清除错误记录次数
	} else {
		_ = redis.Set("", retryKey, retryCount+1, lockTime)
		return info, fmt.Errorf("login.errNameOrPasswd")
	}

	// 登录用户信息
	info.UserId = sysUser.UserId
	info.DeptId = sysUser.DeptId
	info.User = sysUser
	// 用户权限组标识
	if config.IsSystemUser(sysUser.UserId) {
		info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM}
	} else {
		perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId)
		info.Permissions = parse.RemoveDuplicates(perms)
	}
	return info, nil
}

// CleanLoginRecordCache 清除错误记录次数
func (s Account) CleanLoginRecordCache(userName string) bool {
	cacheKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName)
	hasKey, err := redis.Has("", cacheKey)
	if hasKey > 0 && err == nil {
		return redis.Del("", cacheKey) == nil
	}
	return false
}

// passwordRetryCount 密码重试次数
func (s Account) passwordRetryCount(userName string) (string, int64, time.Duration, error) {
	// 从数据库配置获取登录次数和错误锁定时间
	maxRetryCountStr := s.sysConfigService.FindValueByKey("sys.user.maxRetryCount")
	lockTimeStr := s.sysConfigService.FindValueByKey("sys.user.lockTime")
	// 验证登录次数和错误锁定时间
	maxRetryCount := parse.Number(maxRetryCountStr)
	lockTime := parse.Number(lockTimeStr)

	// 验证缓存记录次数
	retryKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName)
	retryCount, err := redis.Get("", retryKey)
	if retryCount == "" || err != nil {
		retryCount = "0"
	}
	// 是否超过错误值
	retryCountInt64 := parse.Number(retryCount)
	if retryCountInt64 >= int64(maxRetryCount) {
		// msg := fmt.Sprintf("密码输入错误 %d 次，帐户锁定 %d 分钟", maxRetryCount, lockTime)
		msg := fmt.Errorf("login.errRetryPasswd") // 密码输入错误多次，帐户已被锁定
		return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, fmt.Errorf("%s", msg)
	}
	return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil
}

// PasswordCountOrExpireTime 首次登录或密码过期时间
func (s Account) PasswordCountOrExpireTime(loginCount, passwordUpdateTime int64) (bool, error) {
	forcePasswdChange := false
	// 从数据库配置获取-首次登录密码修改
	fristPasswdChangeStr := s.sysConfigService.FindValueByKey("sys.user.fristPasswdChange")
	if parse.Boolean(fristPasswdChangeStr) {
		forcePasswdChange = loginCount < 1 || passwordUpdateTime == 0
	}

	// 非首次登录，判断密码是否过期
	if !forcePasswdChange {
		alert, err := s.sysUserService.ValidatePasswordExpireTime(passwordUpdateTime)
		if err != nil {
			return alert, err
		}
		forcePasswdChange = alert
	}
	return forcePasswdChange, nil
}
