package sysUser

import (
	"context"
	"fmt"
	"kami/utility/cache"

	"github.com/duke-git/lancet/v2/pointer"
	"github.com/duke-git/lancet/v2/slice"
	"github.com/shopspring/decimal"

	"kami/internal/consts"

	v1 "kami/api/sys_user_login/v1"
	"kami/internal/dao"
	"kami/internal/errHandler"
	"kami/internal/model"
	"kami/internal/model/do"
	"kami/internal/model/entity"
	"kami/internal/service"
	"kami/utility/config"
	"kami/utility/token"
	"kami/utility/utils"

	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"

	"github.com/gogf/gf/v2/container/gset"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/gogf/gf/v2/util/grand"
	"github.com/mssola/user_agent"
)

func init() {
	service.RegisterSysUser(New())
}

type sSysUser struct {
	casBinUserPrefix string // CasBin 用户id前缀
}

func New() *sSysUser {
	return &sSysUser{
		casBinUserPrefix: "u_",
	}
}

func (s *sSysUser) GetCasBinUserPrefix() string {
	return s.casBinUserPrefix
}

func (s *sSysUser) NotCheckAuthAdminIds(ctx context.Context) *gset.Set {
	ids := g.Cfg().MustGet(ctx, "systemV1.notCheckAuthAdminIds")
	if !g.IsNil(ids) {
		return gset.NewFrom(ids)
	}
	return gset.New()
}

func (s *sSysUser) GetAdminUserByUsernamePassword(ctx context.Context, req *model.UserLoginInput) (user *model.LoginUserOutput, err error) {
	user, err = s.GetUserByUsername(ctx, req.Username)
	if user == nil || err != nil {
		err = gerror.NewCode(gcode.CodeNotAuthorized, "账户名错误")
		return
	}
	// 验证密码
	if utils.EncryptPassword(req.Password, user.UserSalt) != user.UserPassword {
		err = gerror.NewCode(gcode.CodeNotAuthorized, "密码错误")
		return
	}
	////账号状态
	//if user.UserStatus == 0 {
	//	liberr.ErrIsNil(ctx, gerror.New("账号已被冻结"))
	//}
	return
}

// GetUserByUsername 通过用户名获取用户信息
func (s *sSysUser) GetUserByUsername(ctx context.Context, userName string) (sysUser *model.LoginUserOutput, err error) {
	sysUser = &model.LoginUserOutput{}
	err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).Fields(sysUser).
		Where(dao.V1SysUser.Columns().Username, userName).
		Scan(sysUser)
	err = utils.HandleNoRowsError(err)
	return
}

// GetUserById 通过用户名获取用户信息
func (s *sSysUser) GetUserById(ctx context.Context, id string) (sysUser *model.LoginUserOutput, err error) {
	sysUser = &model.LoginUserOutput{}
	err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).Fields(sysUser).WherePri(id).Scan(sysUser)
	return
}

// LoginLog 记录登录日志
func (s *sSysUser) LoginLog(ctx context.Context, params *model.LoginLogParams) {
	ua := user_agent.New(params.UserAgent)
	browser, _ := ua.Browser()
	_, err := dao.V1SysUserLoginLog.Ctx(ctx).DB(config.GetDatabaseV1()).Insert(&do.V1SysUserLoginLog{
		LoginName: params.Username,
		IpAddr:    params.Ip,
		Browser:   browser,
		Os:        ua.OS(),
		Status:    params.Status,
		Message:   params.Msg,
		LoginTime: gtime.Now(),
		Module:    params.Module,
	})
	if err != nil {
		glog.Error(ctx, err)
	}
}

// GetAdminRules 获取用户菜单数据
func (s *sSysUser) GetAdminRules(ctx context.Context, userId string) (menuList []*model.UserMenus, permissions []string, err error) {
	isSuperAdmin := false
	// 获取无需验证权限的用户id
	s.NotCheckAuthAdminIds(ctx).Iterator(func(v interface{}) bool {
		if v == userId {
			isSuperAdmin = true
			return false
		}
		return true
	})
	// 获取用户菜单数据
	allRoles, err := service.SysRole().GetRoleList(ctx)
	if err != nil {
		return
	}
	roles, err := s.GetAdminRole(ctx, userId, allRoles)
	if err != nil {
		return
	}
	name := make([]string, len(roles))
	roleIds := make([]uint, len(roles))
	for k, v := range roles {
		name[k] = v.Name
		roleIds[k] = v.Id
	}
	// 获取菜单信息
	if isSuperAdmin {
		// 超管获取所有菜单
		permissions = []string{"*/*/*"}
		menuList, err = s.GetAllMenus(ctx)
		if err != nil {
			return
		}
	} else {
		menuList, err = s.GetAdminMenusByRoleIds(ctx, roleIds)
		if err != nil {
			return
		}
		permissions, err = s.GetPermissions(ctx, roleIds)
		if err != nil {
			return
		}
	}
	return
}

// GetAdminRole 获取用户角色
func (s *sSysUser) GetAdminRole(ctx context.Context, userId string, allRoleList []*entity.V1SysRole) (roles []*entity.V1SysRole, err error) {
	var roleIds []uint
	roleIds, err = s.GetAdminRoleIds(ctx, userId)
	if err != nil {
		return
	}
	roles = make([]*entity.V1SysRole, 0, len(allRoleList))
	for _, v := range allRoleList {
		for _, id := range roleIds {
			if id == v.Id {
				roles = append(roles, v)
			}
		}
		if len(roles) == len(roleIds) {
			break
		}
	}
	return
}

// GetAdminRoleIds 获取用户角色ids
func (s *sSysUser) GetAdminRoleIds(ctx context.Context, userId string) (roleIds []uint, err error) {
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	// 查询关联角色规则
	groupPolicy, err := enforcer.GetFilteredGroupingPolicy(0, fmt.Sprintf("%s%s", s.casBinUserPrefix, userId))
	if err != nil {
		return
	}
	if len(groupPolicy) > 0 {
		roleIds = make([]uint, len(groupPolicy))
		// 得到角色id的切片
		for k, v := range groupPolicy {
			roleIds[k] = gconv.Uint(v[1])
		}
	}
	return
}

func (s *sSysUser) GetAllMenus(ctx context.Context) (menus []*model.UserMenus, err error) {
	// 获取所有开启的菜单
	var allMenus []*model.SysAuthRuleInfoOutput
	allMenus, err = service.SysAuthRule().GetIsMenuList(ctx)
	if err != nil {
		return
	}
	menus = make([]*model.UserMenus, len(allMenus))
	for k, v := range allMenus {
		var menu *model.UserMenu
		menu = s.setMenuData(menu, v)
		menus[k] = &model.UserMenus{UserMenu: menu}
	}
	menus = s.GetMenusTree(menus, 0)
	return
}

func (s *sSysUser) GetAdminMenusByRoleIds(ctx context.Context, roleIds []uint) (menus []*model.UserMenus, err error) {
	// 获取角色对应的菜单id
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	menuIds := map[int64]int64{}
	for _, roleId := range roleIds {
		// 查询当前权限
		gp, err2 := enforcer.GetFilteredPolicy(0, gconv.String(roleId))
		if err2 != nil {
			return menus, err2
		}
		for _, p := range gp {
			mid := gconv.Int64(p[1])
			menuIds[mid] = mid
		}
	}
	// 获取所有开启的菜单
	allMenus, err := service.SysAuthRule().GetIsMenuList(ctx)
	if err != nil {
		return
	}
	menus = make([]*model.UserMenus, 0, len(allMenus))
	for _, v := range allMenus {
		if _, ok := menuIds[gconv.Int64(v.Id)]; gstr.Equal(v.Condition, "nocheck") || ok {
			var roleMenu *model.UserMenu
			roleMenu = s.setMenuData(roleMenu, v)
			menus = append(menus, &model.UserMenus{UserMenu: roleMenu})
		}
	}
	menus = s.GetMenusTree(menus, 0)
	return
}

func (s *sSysUser) GetMenusTree(menus []*model.UserMenus, pid uint) []*model.UserMenus {
	returnList := make([]*model.UserMenus, 0, len(menus))
	for _, menu := range menus {
		if menu.Pid == pid {
			menu.Children = s.GetMenusTree(menus, menu.Id)
			returnList = append(returnList, menu)
		}
	}
	return returnList
}

func (s *sSysUser) setMenuData(menu *model.UserMenu, entity *model.SysAuthRuleInfoOutput) *model.UserMenu {
	menu = &model.UserMenu{
		UserMenu: v1.UserMenu{
			Id:        entity.Id,
			Pid:       entity.Pid,
			Name:      gstr.CaseCamelLower(gstr.Replace(entity.Name, "/", "_")),
			Component: entity.Component,
			Path:      entity.Path,
			MenuMeta: &v1.MenuMeta{
				Icon:        entity.Icon,
				Title:       entity.Title,
				IsLink:      "",
				IsHide:      entity.IsHide == 1,
				IsKeepAlive: entity.IsCached == 1,
				IsAffix:     entity.IsAffix == 1,
				IsIframe:    entity.IsIframe == 1,
			},
		},
	}
	if menu.MenuMeta.IsIframe || entity.IsLink == 1 {
		menu.MenuMeta.IsLink = entity.LinkUrl
	}
	return menu
}

func (s *sSysUser) GetPermissions(ctx context.Context, roleIds []uint) (userButtons []string, err error) {
	// 获取角色对应的菜单id
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	menuIds := map[int64]int64{}
	for _, roleId := range roleIds {
		// 查询当前权限
		gp, err2 := enforcer.GetFilteredPolicy(0, gconv.String(roleId))
		if err2 != nil {
			return userButtons, err2
		}
		for _, p := range gp {
			mid := gconv.Int64(p[1])
			menuIds[mid] = mid
		}
	}
	// 获取所有开启的按钮
	allButtons, err := service.SysAuthRule().GetIsButtonList(ctx)
	if err != nil {
		return
	}
	userButtons = make([]string, 0, len(allButtons))
	for _, button := range allButtons {
		if _, ok := menuIds[gconv.Int64(button.Id)]; gstr.Equal(button.Condition, "nocheck") || ok {
			userButtons = append(userButtons, button.Name)
		}
	}
	return
}

// List 用户列表
func (s *sSysUser) List(ctx context.Context, req *model.UserSearchInput) (total int, userList []*entity.V1SysUser, err error) {
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	total = 0
	if req.Username != "" {
		m = m.WhereLike(dao.V1SysUser.Columns().Username, utils.OrmLike(req.Username))
	}
	if req.Status != "" {
		m = m.Where(dao.V1SysUser.Columns().UserStatus, gconv.Int(req.Status))
	}
	err = m.FieldsEx(dao.V1SysUser.Columns().UserPassword, dao.V1SysUser.Columns().UserSalt).
		Page(req.Current, req.PageSize).OrderDesc(dao.V1SysUser.Columns().CreatedAt).
		ScanAndCount(&userList, &total, true)
	return
}

func (s *sSysUser) GetByUserName(ctx context.Context, username string) (userList []*entity.V1SysUser, err error) {
	userList = make([]*entity.V1SysUser, 0)
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	if username != "" {
		m = m.WhereLike(dao.V1SysUser.Columns().Username, utils.OrmLike(username))
	}
	err = m.Scan(&userList)
	return
}

// ListWithPayment 查询用户数据，带钱包信息
func (s *sSysUser) ListWithPayment(ctx context.Context, req *model.UserSearchInput) (total int, userList []*model.UserSearchWithPaymentOutput, err error) {
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	total = 0
	if req.Username != "" {
		m = m.WhereLike(dao.V1SysUser.Columns().Username, utils.OrmLike(req.Username))
	}
	if req.Status != "" {
		m = m.Where(dao.V1SysUser.Columns().UserStatus, gconv.Int(req.Status))
	}
	err = m.FieldsEx(dao.V1SysUser.Columns().UserPassword, dao.V1SysUser.Columns().UserSalt).WithAll().
		Page(req.Current, req.PageSize).OrderDesc(dao.V1SysUser.Columns().CreatedAt).
		ScanAndCount(&userList, &total, true)
	return
}

func (s *sSysUser) Add(ctx context.Context, req *model.UserAddInput) (userId string, err error) {
	isExists, err := s.UserNameOrMobileExists(ctx, req.Username)
	if err != nil {
		return
	}
	if isExists {
		err = gerror.NewCode(gcode.CodeOperationFailed, "当前用户存在")
		return
	}
	userSalt := grand.S(10)
	err = config.GetDatabaseV1().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		userId = utils.GenerateRandomUUID()
		_, err2 := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).TX(tx).Save(do.V1SysUser{
			Id:           userId,
			Username:     req.Username,
			UserPassword: utils.EncryptPassword(req.Password, userSalt),
			UserSalt:     userSalt,
			UserStatus:   1,
			IsAdmin:      0,
		})
		if err2 != nil {
			return err2
		}
		err2 = service.SysUserPayment().Add(ctx, model.SysUserPaymentInput{
			UserId: userId,
		}, tx)
		return err2
	})
	return
}

func (s *sSysUser) Edit(ctx context.Context, req *model.UserEditInput) (err error) {
	isExists, err := s.UserNameOrMobileExists(ctx, "", req.ID)
	if err != nil {
		return
	}
	if !isExists {
		err = gerror.NewCode(gcode.CodeNotFound, "用户不存在")
	}
	userSalt := grand.S(10)
	req.Password = utils.EncryptPassword(req.Password, userSalt)
	err = config.GetDatabaseV1().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).TX(tx).WherePri(req.ID).
			Update(do.V1SysUser{
				UserPassword: req.Password,
				UserSalt:     userSalt,
			})
		return err
	})
	return
}

// AddUserRole 添加用户角色信息
func (s *sSysUser) addUserRole(ctx context.Context, roleIds []int64, userId int64) (err error) {
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	for _, v := range roleIds {
		_, err = enforcer.AddGroupingPolicy(fmt.Sprintf("%s%s", s.casBinUserPrefix, userId), gconv.String(v))
		if err != nil {
			return
		}
	}
	return
}

// EditUserRole 修改用户角色信息
func (s *sSysUser) EditUserRole(ctx context.Context, roleIds []int64, userId int64) (err error) {
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	// 删除用户旧角色信息
	_, _ = enforcer.RemoveFilteredGroupingPolicy(0, fmt.Sprintf("%s%s", s.casBinUserPrefix, userId))
	for _, v := range roleIds {
		_, err = enforcer.AddGroupingPolicy(fmt.Sprintf("%s%s", s.casBinUserPrefix, userId), gconv.String(v))
		if err != nil {
			return
		}
	}
	return
}

func (s *sSysUser) UserNameOrMobileExists(ctx context.Context, userName string, id ...string) (isExist bool, err error) {
	user := entity.V1SysUser{}
	isExist = false
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	if userName == "" && len(id) == 0 {
		return
	}
	if len(id) > 0 {
		m = m.Where(dao.V1SysUser.Columns().Id, id[0])
	}
	if userName != "" {
		m = m.Where(dao.V1SysUser.Columns().Username, userName)
	}
	err = m.Limit(1).Scan(&user)
	err = utils.HandleNoRowsError(err)
	if err != nil {
		return
	}
	if user.Id != "" {
		isExist = true
	}
	return
}

// GetEditUser 获取编辑用户信息
func (s *sSysUser) GetEditUser(ctx context.Context, id string) (res *model.UserGetEditOutput, err error) {
	res = new(model.UserGetEditOutput)
	// 获取用户信息
	res.User, err = s.GetUserInfoById(ctx, id)
	if err != nil {
		return
	}
	// 获取已选择的角色信息
	res.CheckedRoleIds, err = s.GetAdminRoleIds(ctx, id)
	return
}

// GetUserInfoById 通过Id获取用户信息
func (s *sSysUser) GetUserInfoById(ctx context.Context, id string, withPwd ...bool) (user *entity.V1SysUser, err error) {
	user = new(entity.V1SysUser)
	if len(withPwd) > 0 && withPwd[0] {
		// 用户用户信息
		err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1SysUser.Columns().Id, id).Scan(&user)
	} else {
		// 用户用户信息
		err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1SysUser.Columns().Id, id).
			FieldsEx(dao.V1SysUser.Columns().UserPassword, dao.V1SysUser.Columns().UserSalt).Scan(&user)
	}
	return
}

// ChangePwd ResetUserPwd 重置用户密码
func (s *sSysUser) ChangePwd(ctx context.Context, input *model.UserChangePwdInput) (err error) {
	salt := grand.S(10)
	password := utils.EncryptPassword(input.NewPassword, salt)
	_, err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).WherePri(input.UserId).Update(do.V1SysUser{
		UserSalt:     salt,
		UserPassword: password,
	})
	return
}

func (s *sSysUser) ChangeUserStatus(ctx context.Context, input *model.UserStatusInput) (err error) {
	_, err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).
		WherePri(input.ID).
		Update(do.V1SysUser{UserStatus: input.UserStatus})
	return
}

// DeleteById 删除用户
func (s *sSysUser) DeleteById(ctx context.Context, id string) (err error) {
	err = config.GetDatabaseV1().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).TX(tx).Where(dao.V1SysUser.Columns().Id, id).Delete()
		return nil
	})
	return
}

// Delete 删除用户
func (s *sSysUser) Delete(ctx context.Context, ids []string) (err error) {
	err = config.GetDatabaseV1().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).TX(tx).WhereIn(dao.V1SysUser.Columns().Id, ids).Delete()
		if err != nil {
			return err
		}
		casbinService := service.Casbin()
		// 删除对应权限
		enforcer, err2 := casbinService.CasbinEnforcer(ctx)
		if err2 != nil {
			return err2
		}
		for _, v := range ids {
			_, _ = enforcer.RemoveFilteredGroupingPolicy(0, fmt.Sprintf("%s%s", s.casBinUserPrefix, v))
		}
		return nil
	})
	return
}

// GetUsers 通过用户ids查询多个用户信息
func (s *sSysUser) GetUsers(ctx context.Context, ids []string) (users []*model.SysUserSimpleOutput, err error) {
	if len(ids) == 0 {
		return
	}
	idsSet := gset.NewStrSetFrom(ids).Slice()
	err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).WhereIn(dao.V1SysUser.Columns().Id, idsSet).
		OrderAsc(dao.V1SysUser.Columns().Id).Scan(&users)
	return
}

// GetUsersAll 获取所有用户
func (s *sSysUser) GetUsersAll(ctx context.Context) (users []*model.SysUserSimpleOutput, err error) {
	err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).OrderAsc(dao.V1SysUser.Columns().CreatedAt).
		Scan(&users)
	err = utils.HandleNoRowsError(err)
	return
}

func (s *sSysUser) GetUserFromToken(ctx context.Context) (needAuth bool, user *entity.V1SysUser, err error) {
	tokenFrom := g.RequestFromCtx(ctx).Request.Header.Get("tokenFrom")
	needAuth = false
	if tokenFrom == "" {
		err = gerror.NewCode(errHandler.ErrTokenExpired, "token失效")
		return
	}
	if tokenFrom == "iframe" {
		return
	}
	needAuth = true
	tokenStr := token.GetTokenFromCtx(ctx)
	if tokenStr == "" {
		err = gerror.NewCode(errHandler.ErrTokenExpired, "token失效")
		return
	}
	userToken, err := token.ParseUserToken(ctx, tokenStr)
	if err != nil {
		return
	}
	userService := service.SysUser()
	user, err2 := userService.GetUserInfoById(ctx, userToken.UserID, true)
	if err2 != nil || user == nil {
		err = errHandler.WrapError(ctx, errHandler.ErrTokenExpired, err, "token失效或用户不存在")
		return
	}
	if user.UserStatus != consts.SysUserStatusNormal {
		err = gerror.NewCode(gcode.CodeNotAuthorized, "用户已被禁用")
	}
	return
}

// CheckUserNormal 检查账户是否正常
func (s *sSysUser) CheckUserNormal(ctx context.Context, userId string) (isNormal bool, err error) {
	isNormal = false
	user, err := s.GetUserInfoById(ctx, userId)
	if err != nil {
		return
	}
	if user.UserStatus == consts.SysUserStatusNormal {
		isNormal = true
	}
	return
}

// GetAllUserNormal 获取所有正常用户
func (s *sSysUser) GetAllUserNormal(ctx context.Context, tx gdb.TX) (user []*entity.V1SysUser, err error) {
	user = make([]*entity.V1SysUser, 0)
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	err = m.Where(dao.V1SysUser.Columns().UserStatus, consts.SysUserStatusNormal).Scan(&user)
	return
}

// GetAllSimpleUser 获取所有的用户
func (s *sSysUser) GetAllSimpleUser(ctx context.Context) (data []model.UserSimpleUsersOutput, err error) {
	data = make([]model.UserSimpleUsersOutput, 0)
	err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).Scan(&data)
	return
}

// GetCurrentOneFromCache 获取当前通道拉的用户
func (s *sSysUser) GetCurrentOneFromCache(ctx context.Context, channelName consts.CardRedeemAccountCategory) (data *entity.V1SysUser, err error) {
	value := cache.NewCache().MustGet(ctx, cache.PrefixRedeemType.Key(channelName))
	if !pointer.IsNil(value) && !value.IsNil() {
		err = dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1SysUser.Columns().Id, value.String()).
			Scan(&data)
	}
	return
}

// GetOneNormalOneWithPayment 获取指定用户，并携带当前充值信息
func (s *sSysUser) GetOneNormalOneWithPayment(ctx context.Context, userId string, tx gdb.TX) (output *model.UserSearchWithPaymentOutput, err error) {
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	err = m.Where(dao.V1SysUser.Columns().Id, userId).Where(dao.V1SysUser.Columns().UserStatus, consts.SysUserStatusNormal).WithAll().Scan(&output)
	return
}

// GetAllNormalWithPayment 获取所有户，并携带当前充值信息
func (s *sSysUser) GetAllNormalWithPayment(ctx context.Context, minAmount float64, tx gdb.TX) (output []*model.UserSearchWithPaymentOutput, err error) {
	output = make([]*model.UserSearchWithPaymentOutput, 0)
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	payment, err := service.SysUserPayment().GetAllByMinAmount(ctx, minAmount, tx)
	if err != nil {
		return
	}
	userIds := make([]string, 0)
	for _, v := range payment {
		userIds = append(userIds, v.UserId)
	}
	err = m.Where(dao.V1SysUser.Columns().UserStatus, consts.SysUserStatusNormal).
		WhereIn(dao.V1SysUser.Columns().Id, userIds).
		WithAll().Scan(&output)
	return
}

// GetAllNormalWithPaymentAndChannelCfg 获取所有户，并携带当前充值信息
func (s *sSysUser) GetAllNormalWithPaymentAndChannelCfg(ctx context.Context, minAmount float64, tx gdb.TX) (output []*model.UserSearchWithPaymentAndCfgOutput, err error) {
	output = make([]*model.UserSearchWithPaymentAndCfgOutput, 0)
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	payment, err := service.SysUserPayment().GetAllByMinAmount(ctx, minAmount, tx)
	if err != nil {
		return
	}
	userIds := make([]string, 0)
	for _, v := range payment {
		userIds = append(userIds, v.UserId)
	}
	err = m.Where(dao.V1SysUser.Columns().UserStatus, consts.SysUserStatusNormal).
		WhereIn(dao.V1SysUser.Columns().Id, userIds).
		WithAll().Scan(&output)
	for i, cfgOutput := range output {
		for _, channelType := range consts.ChannelTypeList {
			targetCfg, ok := slice.FindBy(cfgOutput.ChannelCfg, func(index int, item model.SysUserChannelCfg) bool {
				return item.Name == channelType.String()
			})
			if ok {
				index := slice.IndexOf(cfgOutput.ChannelCfg, targetCfg)
				if targetCfg.Num == 0 && index > 0 && index < len(cfgOutput.ChannelCfg) {
					output[i].ChannelCfg[index].Num = consts.DefaultExchangeConcurrentNum
				}
			} else {
				output[i].ChannelCfg = append(output[i].ChannelCfg, model.SysUserChannelCfg{
					V1SysUserConfigChannel: entity.V1SysUserConfigChannel{
						Name: channelType.String(),
						Num:  consts.DefaultExchangeConcurrentNum,
					},
				})
			}
		}
	}
	return
}

// GetNextOne 获取当前用户的下一个用户
func (s *sSysUser) GetNextOne(ctx context.Context, userId string, amount float64, isNext bool, tx gdb.TX) (data *entity.V1SysUser, err error) {
	list := make([]*entity.V1SysUser, 0)
	m := dao.V1SysUser.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1SysUser.Columns().UserStatus, consts.SysUserStatusNormal).
		OrderAsc(dao.V1SysUser.Columns().CreatedAt)
	if tx != nil {
		m = m.TX(tx)
	}
	currentUser, ok := slice.FindBy(list, func(index int, item *entity.V1SysUser) bool {
		return !pointer.IsNil(item) && item.Id == userId
	})
	currentIndex := 0
	if ok {
		currentIndex = slice.IndexOf(list, currentUser)
		if isNext {
			currentIndex = (currentIndex + 1) % len(list)
		}
	}
	err = m.Scan(&list)
	for i := 0; i < len(list); i++ {
		isEnough, _ := service.SysUserPayment().CheckAmountEnough(ctx, &model.SysUserPaymentCheckBalanceInput{
			UserId: currentUser.Id,
			Amount: decimal.NewFromFloat(amount),
		})
		if isEnough {
			break
		}
		currentUser = list[(currentIndex+i)%len(list)]
	}
	data = currentUser
	return
}
