package service

import (
	"fmt"
	"time"

	"nms_nbi/src/framework/config"
	adminConstants "nms_nbi/src/framework/constants/admin"
	"nms_nbi/src/framework/constants/cachekey"
	"nms_nbi/src/framework/constants/common"
	"nms_nbi/src/framework/redis"
	"nms_nbi/src/framework/utils/crypto"
	"nms_nbi/src/framework/utils/parse"
	"nms_nbi/src/framework/vo"
	"nms_nbi/src/modules/system/model"
	systemService "nms_nbi/src/modules/system/service"
)

// 实例化服务层 AccountImpl 结构体
var NewAccountImpl = &AccountImpl{
	sysUserService:   systemService.NewSysUserImpl,
	sysConfigService: systemService.NewSysConfigImpl,
	sysRoleService:   systemService.NewSysRoleImpl,
	sysMenuService:   systemService.NewSysMenuImpl,
}

// 账号身份操作服务 服务层处理
type AccountImpl struct {
	// 用户信息服务
	sysUserService systemService.ISysUser
	// 参数配置服务
	sysConfigService systemService.ISysConfig
	// 角色服务
	sysRoleService systemService.ISysRole
	// 菜单服务
	sysMenuService systemService.ISysMenu
}

// ValidateCaptcha 校验验证码
func (s *AccountImpl) ValidateCaptcha(code, uuid string) error {
	// 验证码检查，从数据库配置获取验证码开关 true开启，false关闭
	captchaEnabledStr := s.sysConfigService.SelectConfigValueByKey("sys.account.captchaEnabled")
	if !parse.Boolean(captchaEnabledStr) {
		return nil
	}
	if code == "" || uuid == "" {
		// 验证码信息错误
		return fmt.Errorf("captcha.err")
	}
	verifyKey := cachekey.CAPTCHA_CODE_KEY + 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
}

// LoginByUsername 登录创建用户信息
func (s *AccountImpl) LoginByUsername(username, password string) (vo.LoginUser, error) {
	loginUser := vo.LoginUser{}

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

	// 查询用户登录账号
	sysUser := s.sysUserService.SelectUserByUserName(username)
	if sysUser.UserName != username {
		return loginUser, fmt.Errorf("login.errNameOrPasswd")
	}
	if sysUser.DelFlag == common.STATUS_YES {
		// 对不起，您的账号已被删除
		return loginUser, fmt.Errorf("login.errDelFlag")
	}
	if sysUser.Status == common.STATUS_NO {
		return loginUser, fmt.Errorf("login.errStatus")
	}

	// 检验用户密码
	compareBool := crypto.BcryptCompare(password, sysUser.Password)
	if !compareBool {
		redis.SetByExpire("", retrykey, retryCount+1, lockTime)
		// 用户不存在或密码错误
		return loginUser, fmt.Errorf("login.errNameOrPasswd")
	} else {
		// 清除错误记录次数
		s.ClearLoginRecordCache(username)
	}

	// 登录用户信息
	loginUser.UserID = sysUser.UserID
	loginUser.DeptID = sysUser.DeptID
	loginUser.User = sysUser
	// 用户权限组标识
	isAdmin := config.IsAdmin(sysUser.UserID)
	if isAdmin {
		loginUser.Permissions = []string{adminConstants.PERMISSION}
	} else {
		perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID)
		loginUser.Permissions = parse.RemoveDuplicates(perms)
	}
	return loginUser, nil
}

// UpdateLoginDateAndIP 更新登录时间和IP
func (s *AccountImpl) UpdateLoginDateAndIP(loginUser *vo.LoginUser) bool {
	sysUser := loginUser.User
	userInfo := model.SysUser{
		UserID:    sysUser.UserID,
		LoginIP:   sysUser.LoginIP,
		LoginDate: sysUser.LoginDate,
		UpdateBy:  sysUser.UserName,
	}
	rows := s.sysUserService.UpdateUser(userInfo)
	return rows > 0
}

// ClearLoginRecordCache 清除错误记录次数
func (s *AccountImpl) ClearLoginRecordCache(username string) bool {
	cacheKey := cachekey.PWD_ERR_CNT_KEY + username
	hasKey, _ := redis.Has("", cacheKey)
	if hasKey {
		delOk, _ := redis.Del("", cacheKey)
		return delOk
	}
	return false
}

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

	// 验证登录次数和错误锁定时间
	maxRetryCount := parse.Number(maxRetryCountStr)
	lockTime := parse.Number(lockTimeStr)
	// 验证缓存记录次数
	retrykey := cachekey.PWD_ERR_CNT_KEY + username
	retryCount, err := redis.Get("", retrykey)
	if retryCount == "" || err != nil {
		retryCount = "0"
	}
	// 是否超过错误值
	retryCountInt64 := parse.Number(retryCount)
	if retryCountInt64 >= maxRetryCount {
		// 密码输入错误多次，帐户已被锁定
		errorMsg := fmt.Errorf("login.errRetryPasswd")
		return retrykey, retryCountInt64, time.Duration(lockTime) * time.Minute, errorMsg
	}
	return retrykey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil
}

// RoleAndMenuPerms 角色和菜单数据权限
func (s *AccountImpl) RoleAndMenuPerms(userId string, isAdmin bool) ([]string, []string) {
	if isAdmin {
		return []string{adminConstants.ROLE_KEY}, []string{adminConstants.PERMISSION}
	} else {
		// 角色key
		roleGroup := []string{}
		roles := s.sysRoleService.SelectRoleListByUserId(userId)
		for _, role := range roles {
			roleGroup = append(roleGroup, role.RoleKey)
		}
		// 菜单权限key
		perms := s.sysMenuService.SelectMenuPermsByUserId(userId)
		return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms)
	}
}

// RouteMenus 前端路由所需要的菜单
func (s *AccountImpl) RouteMenus(userId string, isAdmin bool) []vo.Router {
	var buildMenus []vo.Router
	if isAdmin {
		menus := s.sysMenuService.SelectMenuTreeByUserId("*")
		buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
	} else {
		menus := s.sysMenuService.SelectMenuTreeByUserId(userId)
		buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
	}
	return buildMenus
}
