package user_cv

import (
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/mylogrus"
	"git.hilo.cn/hilo-common/resource/mysql"
	"git.hilo.cn/hilo-common/rpc"
	. "git.hilo.cn/hilo-common/utils"
	"gorm.io/gorm"
	"hilo-group/_const/enum/groupPower_e"
	"hilo-group/_const/enum/group_e"
	"hilo-group/_const/enum/user_e"
	"hilo-group/cv/country_cv"
	"hilo-group/cv/diamond_cv"
	"hilo-group/cv/headwear_cv"
	"hilo-group/cv/medal_cv"
	"hilo-group/cv/noble_cv"
	"hilo-group/cv/property_cv"
	"hilo-group/domain/model/country_m"
	"hilo-group/domain/model/groupPower_m"
	"hilo-group/domain/model/group_m"
	"hilo-group/domain/model/noble_m"
	"hilo-group/domain/model/res_m"
	"hilo-group/domain/model/user_m"
	"hilo-group/domain/model/visit_m"
	"hilo-group/myerr"
)

//用户详细信息
type CvUserDetail struct {
	CvUserBase
	//统计:我喜欢多少人
	ILikeCount *uint32 `json:"iLikeCount"`
	//统计:多少人喜欢你, (本才才有数据,不是本人,数据为nil)
	LikeCount *uint32 `json:"likeCount"`
	//统计:多少人访问你
	VisitCount *uint32 `json:"visitCount"`
	//消息提醒, 1:开启,2:关闭
	IsPush *uint8 `json:"isPush"`
	//钻石数量(本人才有数据,不是本人,数据为nil)
	DiamondNum *uint32 `json:"diamondNum"`
	//粉钻数量(本人才有数据,不是本人,数据为nil)
	PinkDiamondNum *uint32 `json:"pinkDiamondNum"`
	//是否喜欢(本人没有数据,//20210205 已废弃nil,产品说:可以自己喜欢自己)
	IsLike *bool `json:"isLike"`
	//ID
	//ID *mysql.ID `json:"id,omitempty"`
	//是否工会成员, 只有是自己查自己,这个才有值,其它全为nil
	//IsTradeUnion *bool `json:"isTradeUnion"`
	//工会成员,是否开启了,匹配通知,只有 isTradeUnion值为true,这里才有值,
	//IsTradeUnionMatchNotification *bool `json:"isTradeUnionMatchNotification"`
	//是否可以免费通话,自己本人没有数据
	//IsVideoFreeCan *bool `json:"isVideoCanFree"`
	//别人是否喜欢我,自己本人没有数据 (20210205 已废弃nil,产品说:可以自己喜欢自己)
	IsLikeMe          *bool                        `json:"isLikeMe"`
	HeartValue        uint32                       `json:"heartValue"`               // 与我之间永恒之心的值
	HeartValueMax     uint32                       `json:"heartValueMax"`            // 与我之间永恒之心的最大值(0代表没有永恒之心,即没有相互关注)
	MeetDays          uint                         `json:"meetDays"`                 // 成长关系建立的时间(天数)
	WealthUserGrade   uint32                       `json:"wealthUserGrade"`          //财富等级
	CharmUserGrade    uint32                       `json:"charmUserGrade"`           //魅力等级
	ActivityUserGrade uint32                       `json:"activityUserGrade"`        //活跃等级
	CurrentRoom       string                       `json:"currentRoom"`              // 当前用户所在房间(产品叫“群组”)
	MyGroupPower      uint64                       `json:"myGroupPower"`             // 当前用户所在势力
	MyGroupPowerName  string                       `json:"myGroupPowerName"`         // 当前用户所在势力绑定群组的名称
	GroupPower        GroupPower                   `json:"groupPower"`               // 当前用户势力信息
	GroupId           string                       `json:"groupId"`                  // 当前用户拥有的群组id(产品叫“群组”),如果没有则为空,拥有多个,返回第一个
	PhoneInfo         *user_m.UserPhoneInfo        `json:"phoneInfo"`                // 用户绑定的手机信息
	ThirdList         []int8                       `json:"thirdList"`                // 用户绑定的第三方平台列表;类型 1:phone, 2:google, 3:facebook 4:apple 5:wechat" Enums(1,2,3,4,5)
	CountryManager    *country_cv.CVCountryManager `json:"countryManager,omitempty"` // 国家管理员
}

type GroupPower struct {
	Id        uint64                       `json:"id"`                  // 群主所在的势力ID
	Icon      string                       `json:"icon"`                // 家族头像
	Name      string                       `json:"name"`                // 群主所在的势力的名称
	Nameplate string                       `json:"nameplate"`           // 势力铭牌
	Grade     groupPower_e.GroupPowerGrade `json:"grade"`               // 等级
	MemberNum uint32                       `json:"memberNum,omitempty"` // 当前成员数
	MemberMax uint32                       `json:"memberMax,omitempty"` // 成员上限
}

type CvUserTiny struct {
	Id           uint64 `json:"id,omitempty"`
	ExternalId   string `json:"externalId"`
	Avatar       string `json:"avatar"`
	Nick         string `json:"nick"`
	Sex          uint8  `json:"sex"`
	Code         string `json:"code"`
	Country      string `json:"country"`
	CountryIcon  string `json:"countryIcon"`
	IsPrettyCode bool   `json:"isPrettyCode"` // 是否靓号
	IsLogout     bool   `json:"isLogout"`     //是否注销 true:已经注销, false:没有注销
	//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
	Birthday *uint64 `json:"birthday"`
}

//用户基本信息
type CvUserBase struct {
	//不会有返回值
	Id *mysql.ID `json:"id,omitempty"`
	//头像,不存在为nil
	Avatar *string `json:"avatar"`
	//是否默认头像 true:是 false:不是
	DefaultAvatar *bool `json:"defaultAvatar"`
	//用户对外ID
	ExternalId *string `json:"externalId"`
	//昵称,不存在为nil
	Nick *string `json:"nick"`
	//签名,不存在为nil
	Description *string `json:"description"`
	//性别 1:男 2:女,不存在为nil
	Sex *uint8 `json:"sex"`
	//国家,不存在为nil
	Country *string `json:"country"`
	//国旗图标,不存在为nil
	CountryIcon *string `json:"countryIcon"`
	//邀请码
	Code         *string `json:"code"`
	IsPrettyCode bool    `json:"isPrettyCode"` // 是否靓号
	IsLogout     bool    `json:"isLogout"`     //是否注销
	//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
	Birthday *uint64 `json:"birthday"`
	//是否展示年龄, 是本人才有数据,看其他用户均为nil
	IsShowAge *uint8 `json:"isShowAge"`
	//是否工会成员, 只有是自己查自己,这个才有值,其它全为nil, 20220329 数据开放:原因:产品1对1视频聊天中,公会用户视频需要送礼物。改为: 全部人可以知道是否是公会用户。
	IsTradeUnion *bool `json:"isTradeUnion"`
	//是否代理管理员, 只有自己查自己的时候才有值,其他情况为nil
	IsAgentMgr *bool `json:"isAgentMgr"`
	//工会成员,是否开启了,匹配通知,只有 isTradeUnion值为true,这里才有值,
	IsTradeUnionMatchNotification *bool `json:"isTradeUnionMatchNotification"`
	//是否VIP用户
	IsVip bool `json:"isVip"`
	//是否是官方人员
	IsOfficialStaff bool `json:"isOfficialStaff"`
	//VIP用户过期时间(只有自己查询自己,才返回)
	VipExpireTime *int64                  `json:"vipExpireTime"`
	Svip          rpc.CvSvip              `json:"svip"`      // svip结构,等级+权限
	Medals        []uint32                `json:"medals"`    // 勋章列表 TODO: 删除
	MedalInfo     []medal_cv.CvMedal      `json:"medalInfo"` // 勋章列表
	Headwear      *headwear_cv.CvHeadwear `json:"headwear"`  // 当前使用的头饰
	Ride          property_cv.CvProperty  `json:"ride"`      // 当前使用的座驾
	Noble         noble_cv.CvNoble        `json:"noble"`     // 当前的
	GroupRole     group_e.GroupRoleType   `json:"groupRole"` // 在群组的角色
}

type CvUserExtend struct {
	CvUserBase
	WealthGrade uint32 `json:"wealthUserGrade"`
	CharmGrade  uint32 `json:"charmUserGrade"`
	ActiveGrade uint32 `json:"activityUserGrade"`
}

// 批量获取用户tiny信息
func GetUserTinyMap(userIds []mysql.ID) (map[mysql.ID]CvUserTiny, error) {
	userTinys, _, err := GetUserTinys(userIds)
	if err != nil {
		return nil, err
	}
	result := make(map[mysql.ID]CvUserTiny, 0)
	for i, _ := range userTinys {
		result[userTinys[i].Id] = userTinys[i]
	}
	return result, nil
}

//批量获取用户tiny信息
func GetUserTinys(userIds []mysql.ID) ([]CvUserTiny, []uint64, error) {
	if len(userIds) == 0 {
		return nil, nil, nil
	}
	var users []user_m.User
	if err := mysql.Db.Model(&user_m.User{}).Where("id IN ?", userIds).Find(&users).Error; err != nil {
		return nil, nil, myerr.WrapErr(err)
	}
	userTinys := make([]CvUserTiny, 0, len(users))
	for _, r := range users {
		userTinys = append(userTinys, GetUserTinyBy(r))
	}
	return userTinys, userIds, nil
}

func GetUserTinyBy(user user_m.User) CvUserTiny {
	return CvUserTiny{
		Id:           user.ID,
		Avatar:       IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar),
		ExternalId:   user.ExternalId,
		Nick:         IfLogoutNick(IfLogout(user.LogoutTime), user.Code, user.Nick),
		Sex:          user.Sex,
		Code:         user.Code,
		Country:      user.Country,
		CountryIcon:  user.CountryIcon,
		IsPrettyCode: user.IsPrettyCode(),
		IsLogout:     IfLogout(user.LogoutTime),
		Birthday:     BirthdayToUint64(&user.Birthday),
	}
}

func GetUserDetailMap(userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]*CvUserDetail, error) {
	cvUserDetails, err := GetUserDetailByIds(userIds, myUserId)
	if err != nil {
		return map[mysql.ID]*CvUserDetail{}, err
	}
	//转换成map
	mapIdUser := map[mysql.ID]*CvUserDetail{}
	for i := 0; i < len(cvUserDetails); i++ {
		mapIdUser[*cvUserDetails[i].Id] = cvUserDetails[i]
	}
	return mapIdUser, nil
}

func GetUserDetailByIds(userIds []mysql.ID, myUserId mysql.ID) ([]*CvUserDetail, error) {
	if len(userIds) == 0 {
		return nil, nil
	}

	model := domain.CreateModelNil()

	var users []*user_m.User
	if err := model.DB().Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	cvUserDetails, err := getUserDetails(model, users, myUserId)
	if err != nil {
		return nil, err
	}
	return cvUserDetails, nil
}

func getUserDetails(model *domain.Model, users []*user_m.User, myUserId mysql.ID) ([]*CvUserDetail, error) {
	//找出所有user.id
	userIds := []mysql.ID{}
	for i := 0; i < len(users); i++ {
		userIds = append(userIds, users[i].ID)
	}
	//查找喜欢
	var userLikes []user_m.UserLike
	if err := mysql.Db.Where(&user_m.UserLike{
		UserId: myUserId,
	}).Where("like_user_id in (?)", userIds).Find(&userLikes).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	//喜欢组成map
	likeMap := map[mysql.ID]bool{}
	for i := 0; i < len(userLikes); i++ {
		likeMap[userLikes[i].LikeUserId] = true
	}
	//查找喜欢我的
	userLikeMes := []user_m.UserLike{}
	if err := mysql.Db.Where(&user_m.UserLike{
		LikeUserId: myUserId,
	}).Where("user_id in (?)", userIds).Find(&userLikeMes).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	//喜欢组成map
	likeMeMap := map[mysql.ID]bool{}
	for i := 0; i < len(userLikeMes); i++ {
		likeMeMap[userLikeMes[i].UserId] = true
	}

	rels, _ := BatchGetRelations(myUserId, userIds)

	wealthGradeMap, err := BatchGetWealthGrade(userIds)
	if err != nil {
		return nil, err
	}
	charmGradeMap, err := BatchGetCharmGrade(userIds)
	if err != nil {
		return nil, err
	}
	activeGradeMap, err := BatchGetActiveGrade(userIds)
	if err != nil {
		return nil, err
	}

	vips, err := user_m.BatchGetVips(userIds)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}
	svips, err := rpc.MGetUserSvip(model, userIds)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}

	headwearMap, err := headwear_cv.BatchGetCvHeadwears(userIds)
	if err != nil {
		return nil, err
	}

	medals, err := user_m.BatchGetUserMedalMerge(model.Log, mysql.Db, userIds)
	if err != nil {
		return nil, err
	}

	medals, medalInfo, err := medal_cv.GetMedalInfoMap(mysql.Db, medals)
	if err != nil {
		return nil, err
	}

	rooms, err := group_m.RoomLivingUserIdFilter(userIds)
	if err != nil {
		return nil, err
	}
	model.Log.Infof("getUserDetails: %+v", rooms)

	// userId->groupPowerId
	groupPowers, err := groupPower_m.GetGroupPowerMap(mysql.Db, userIds)
	if err != nil {
		return nil, err
	}

	gpIds := make([]uint64, 0)
	for _, i := range groupPowers {
		gpIds = append(gpIds, i)
	}
	powerNames, _, err := groupPower_m.GetGroupPowerNames(mysql.Db, gpIds)
	if err != nil {
		return nil, err
	}
	groupPowerInfoMap, err := groupPower_m.MGetGroupPowerInfoMap(model, gpIds)
	if err != nil {
		return nil, err
	}
	groupPowerGradeMap, err := groupPower_m.MGetGroupPowerGrade(model, gpIds)
	if err != nil {
		return nil, err
	}
	groupPowerUsers, err := groupPower_m.MGetGroupPowerUsers(model, gpIds)
	if err != nil {
		return nil, err
	}
	// 成员上限

	groupPowerNames := make(map[mysql.ID]string, 0)
	groupPowerInfos := make(map[mysql.ID]groupPower_m.GroupPowerInfo)
	groupPowerGrades := make(map[mysql.ID]groupPower_m.GroupPowerGrade)
	groupPowerMembers := make(map[mysql.ID][2]int) // 0->memberNum 1->memberLimit
	for uid, gid := range groupPowers {
		groupPowerNames[uid] = powerNames[gid]
		groupPowerInfos[uid] = groupPowerInfoMap[gid]
		groupPowerGrades[uid] = groupPowerGradeMap[gid]
		var memberMax int
		grade := groupPowerGradeMap[gid].Grade
		if grade >= groupPower_e.GroupPowerGrade0 && grade <= groupPower_e.GroupPowerGradeMax {
			if grade == groupPower_e.GroupPowerGrade0 {
				memberMax = 300
			}
			if grade == groupPower_e.GroupPowerGrade1 {
				memberMax = 500
			}
			if grade == groupPower_e.GroupPowerGrade2 {
				memberMax = 800
			}
			if grade == groupPower_e.GroupPowerGrade3 {
				memberMax = 1200
			}
		}
		memberNum := len(groupPowerUsers[gid])
		if memberNum > memberMax {
			memberMax = memberNum
		}
		groupPowerMembers[uid] = [2]int{memberNum, memberMax}
	}

	up := user_m.UserProperty{}
	rides, err := up.BatchGet(mysql.Db, userIds)
	if err != nil {
		return nil, err
	}

	rp := res_m.ResProperty{}
	properties, err := rp.GetAll(mysql.Db)
	if err != nil {
		return nil, err
	}

	nobles, err := noble_m.BatchGetActiveNoble(mysql.Db, userIds)
	if err != nil {
		return nil, err
	}

	//判断是不是工会
	userTradeUnion, err := user_m.GetUserTradeUnion(myUserId)
	if err != nil {
		return nil, err
	}

	superManagerMap, err := user_m.GetSuperManagerMap(userIds)
	if err != nil {
		return nil, err
	}

	cvUserDetails := []*CvUserDetail{}
	for i := 0; i < len(users); i++ {
		var headwear *headwear_cv.CvHeadwear = nil
		if headwearTemp, flag := headwearMap[users[i].ID]; flag {
			headwear = &headwearTemp
		}
		ride := property_cv.CvProperty{
			Id:        properties[rides[users[i].ID]].ID,
			PicUrl:    properties[rides[users[i].ID]].PicUrl,
			EffectUrl: properties[rides[users[i].ID]].EffectUrl,
		}

		cvUserDetail, err := userToDetail(users[i], myUserId, userTradeUnion, likeMap, likeMeMap, rels,
			vips[users[i].ID] != nil, vips[users[i].ID], svips[users[i].ID], headwear, ride,
			wealthGradeMap, charmGradeMap, activeGradeMap, medals, medalInfo, rooms, groupPowers, groupPowerNames, groupPowerInfos, groupPowerGrades, groupPowerMembers, nobles, superManagerMap)
		if err != nil {
			return nil, err
		}

		cvUserDetail.CurrentRoom, err = group_m.ToTxGroupId(model, cvUserDetail.CurrentRoom)
		if err != nil {
			return nil, err
		}

		cvUserDetails = append(cvUserDetails, cvUserDetail)
	}
	return cvUserDetails, nil
}

//转换
func userToDetail(user *user_m.User, myUserId mysql.ID, userTradeUnion *user_m.UserTradeUnion, likeMap map[mysql.ID]bool,
	likeMeMap map[mysql.ID]bool, hvMap map[mysql.ID]Relation, isVip bool, vipExpireTime *int64, svip rpc.CvSvip, headwear *headwear_cv.CvHeadwear, ride property_cv.CvProperty,
	wealthGradeMap map[mysql.ID]uint32, charmGradeMap map[mysql.ID]uint32, actityGradeMap map[mysql.ID]uint32,
	medals map[uint64][]uint32, medalInfo map[uint64][]medal_cv.CvMedal, rooms map[mysql.ID]string,
	powers map[mysql.ID]uint64, powerNames map[mysql.ID]string, groupPowerInfos map[mysql.ID]groupPower_m.GroupPowerInfo, powerGrades map[mysql.ID]groupPower_m.GroupPowerGrade, groupPowerMembers map[mysql.ID][2]int, nobles map[mysql.ID]noble_m.UserNoble, superManagerMap map[uint64]bool) (*CvUserDetail, error) {
	cvUserDetail := &CvUserDetail{
		CvUserBase: CvUserBase{
			Id:              &user.ID,
			Avatar:          StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar)),
			DefaultAvatar:   &user.DefaultAvatar,
			ExternalId:      StrToString(&user.ExternalId),
			Nick:            StrNil(IfLogoutNick(IfLogout(user.LogoutTime), user.Code, user.Nick)),
			Description:     StrNil(user.Description),
			Sex:             TypeToUint8((*mysql.Type)(&user.Sex)),
			Country:         StrNil(user.Country),
			CountryIcon:     StrNil(user.CountryIcon),
			Code:            StrToString(&user.Code),
			IsPrettyCode:    user.IsPrettyCode(),
			IsVip:           isVip,
			IsOfficialStaff: superManagerMap[user.ID],
			VipExpireTime:   vipExpireTime,
			Svip:            svip,
			Medals:          IfLogoutMedals(IfLogout(user.LogoutTime), []uint32{}, medals[user.ID]),
			MedalInfo:       IfLogoutMedalInfo(IfLogout(user.LogoutTime), []medal_cv.CvMedal{}, medalInfo[user.ID]),
			Headwear:        IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, headwear),
			Ride:            IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, ride),
		},
		IsPush: TypeToUint8((*mysql.Type)(&user.IsPush)),
	}
	//本人,计算,喜欢统计,钻石数量
	if user.ID == myUserId {
		cvUserDetail.IsShowAge = TypeToUint8((*mysql.Type)(&user.IsShowAge))
		cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday)

		//喜欢统计
		var userCount user_m.UserCount
		err := mysql.Db.Where(&user_m.UserCount{
			UserId: myUserId,
			Type:   user_e.CountTypeLikeMe,
		}).First(&userCount).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, myerr.WrapErr(err)
		}
		cvUserDetail.LikeCount = NumToUint32(&userCount.Num)

		//我喜欢统计
		var userILikeCount user_m.UserCount
		err = mysql.Db.Where(&user_m.UserCount{
			UserId: myUserId,
			Type:   user_e.CountTypeLike,
		}).First(&userILikeCount).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, myerr.WrapErr(err)
		}
		cvUserDetail.ILikeCount = NumToUint32(&userILikeCount.Num)

		//访问统计
		var visitCount int64
		err = mysql.Db.Model(&visit_m.UserVisit{}).Where(&visit_m.UserVisit{
			VisitUserId: myUserId,
		}).Count(&visitCount).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, myerr.WrapErr(err)
		}
		vc := uint32(visitCount)
		cvUserDetail.VisitCount = NumToUint32((*mysql.Num)(&vc))

		//钻石数量
		cvDiamond, err := diamond_cv.GetDiamond(myUserId)
		if err != nil {
			return nil, err
		}
		cvUserDetail.DiamondNum = cvDiamond.DiamondNum
		cvUserDetail.PinkDiamondNum = cvDiamond.PinkDiamondNum

		isAgent := user_m.IsAgent(myUserId)
		cvUserDetail.IsAgentMgr = &isAgent
	} else {
		//不是本人
		if user.IsShowAge == mysql.OPEN {
			cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday)
		}
	}

	if userTradeUnion == nil {
		isTradeUnionFlag := false
		cvUserDetail.IsTradeUnion = &isTradeUnionFlag
		cvUserDetail.IsTradeUnionMatchNotification = nil
	} else {
		isTradeUnionFlag := true
		cvUserDetail.IsTradeUnion = &isTradeUnionFlag
		isTradeUnionMatchNotificationFlag := userTradeUnion.MatchNotification == mysql.OPEN
		cvUserDetail.IsTradeUnionMatchNotification = &isTradeUnionMatchNotificationFlag
	}

	//喜欢
	flag, ok := likeMap[user.ID]
	if ok {
		cvUserDetail.IsLike = &flag
	} else {
		flag := false
		cvUserDetail.IsLike = &flag
	}
	//是否喜欢我
	likeMeFlag, ok := likeMeMap[user.ID]
	if ok {
		cvUserDetail.IsLikeMe = &likeMeFlag
	} else {
		islikeMe := false
		cvUserDetail.IsLikeMe = &islikeMe
	}
	// 永恒之心的值
	hv, ok := hvMap[user.ID]
	if ok {
		cvUserDetail.HeartValue = hv.HeartValue
		cvUserDetail.HeartValueMax = hv.HeartValueMax
		cvUserDetail.MeetDays = hv.MeetDays
	} else {
		cvUserDetail.HeartValueMax = 0
	}
	//财富等级
	wGroup, ok := wealthGradeMap[user.ID]
	if ok {
		cvUserDetail.WealthUserGrade = wGroup
	} else {
		cvUserDetail.WealthUserGrade = 0
	}
	//魅力等级
	cGroup, ok := charmGradeMap[user.ID]
	if ok {
		cvUserDetail.CharmUserGrade = cGroup
	} else {
		cvUserDetail.CharmUserGrade = 0
	}
	//活跃等级
	aGroup, ok := actityGradeMap[user.ID]
	if ok {
		cvUserDetail.ActivityUserGrade = aGroup
	} else {
		cvUserDetail.ActivityUserGrade = 0
	}
	cvUserDetail.CurrentRoom = rooms[user.ID]
	cvUserDetail.MyGroupPower = powers[user.ID]
	cvUserDetail.MyGroupPowerName = powerNames[user.ID]
	cvUserDetail.GroupPower = GroupPower{
		Id:        groupPowerInfos[user.ID].ID,
		Icon:      groupPowerInfos[user.ID].Icon,
		Name:      groupPowerInfos[user.ID].Name,
		Nameplate: groupPowerInfos[user.ID].Nameplate,
		Grade:     powerGrades[user.ID].Grade,
		MemberNum: mysql.Num(groupPowerMembers[user.ID][0]),
		MemberMax: mysql.Num(groupPowerMembers[user.ID][1]),
	}
	if n, ok := nobles[user.ID]; ok && n.Level > 0 {
		cvUserDetail.Noble = noble_cv.CvNoble{
			Level:   n.Level,
			EndTime: n.EndTime.Unix(),
		}
	}
	return cvUserDetail, nil
}

func IfLogoutMedals(condition bool, trueVal, falseVal []uint32) []uint32 {
	if condition {
		return trueVal
	}
	return falseVal
}

func IfLogoutMedalInfo(condition bool, trueVal, falseVal []medal_cv.CvMedal) []medal_cv.CvMedal {
	if condition {
		return trueVal
	}
	return falseVal
}

func IfLogoutHeadwear(condition bool, trueVal, falseVal *headwear_cv.CvHeadwear) *headwear_cv.CvHeadwear {
	if condition {
		return trueVal
	}
	return falseVal
}

func IfLogoutRide(condition bool, trueVal, falseVal property_cv.CvProperty) property_cv.CvProperty {
	if condition {
		return trueVal
	}
	return falseVal
}

//用户基本信息
func GetUserDetail(model *domain.Model, userId mysql.ID, myUserId mysql.ID) (*CvUserDetail, error) {
	model.Log.Infof("GetUserDetail %d begin", userId)
	var user user_m.User
	var err error
	if err = mysql.Db.First(&user, userId).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}

	//统计喜欢
	var likeN int64
	if err := mysql.Db.Model(&user_m.UserLike{}).Where(&user_m.UserLike{
		UserId:     myUserId,
		LikeUserId: userId,
	}).Count(&likeN).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}

	var likeMe int64
	if err := mysql.Db.Model(&user_m.UserLike{}).Where(&user_m.UserLike{
		UserId:     userId,
		LikeUserId: myUserId,
	}).Count(&likeMe).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}

	rel := make(map[mysql.ID]Relation, 1)
	rel[userId], _ = GetRelation(myUserId, userId)

	var wealthUserScore user_m.MatchWealthUserScore
	if err := mysql.Db.Model(&user_m.MatchWealthUserScore{}).Where(&user_m.MatchWealthUserScore{UserId: userId}).First(&wealthUserScore).Error; err != nil {
		if err != nil {
			if err == gorm.ErrRecordNotFound {
				wealthUserScore = user_m.MatchWealthUserScore{
					UserId: userId,
					Score:  0,
					Grade:  0,
				}
			} else {
				return nil, myerr.WrapErr(err)
			}
		}
	}

	var charmUserScore user_m.MatchCharmUserScore
	if err := mysql.Db.Model(&user_m.MatchCharmUserScore{}).Where(&user_m.MatchCharmUserScore{
		UserId: userId,
	}).First(&charmUserScore).Error; err != nil {
		if err != nil {
			if err == gorm.ErrRecordNotFound {
				charmUserScore = user_m.MatchCharmUserScore{
					UserId: userId,
					Score:  0,
					Grade:  0,
				}
			} else {
				return nil, myerr.WrapErr(err)
			}
		}
	}

	var activityUserScore user_m.MatchActityUserScore
	if err := mysql.Db.Model(&user_m.MatchActityUserScore{}).Where(&user_m.MatchActityUserScore{
		UserId: userId,
	}).First(&activityUserScore).Error; err != nil {
		if err != nil {
			if err == gorm.ErrRecordNotFound {
				activityUserScore = user_m.MatchActityUserScore{
					UserId: userId,
					Score:  0,
					Grade:  0,
				}
			} else {
				return nil, myerr.WrapErr(err)
			}
		}
	}
	isVip, expireTime, err := user_m.IsVip(userId)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}
	svip, err := rpc.GetUserSvip(model, userId)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}

	headwear, err := headwear_cv.GetCvHeadwear(userId)
	if err != nil {
		return nil, err
	}

	medals := make(map[uint64][]uint32, 0)
	medals[userId], err = user_m.GetUserMedalMerge(model.Log, mysql.Db, userId)
	if err != nil {
		return nil, err
	}

	medals, medalInfo, err := medal_cv.GetMedalInfoMap(mysql.Db, medals)
	if err != nil {
		return nil, err
	}

	rooms, err := group_m.RoomLivingUserIdFilter([]uint64{userId})
	if err != nil {
		return nil, err
	}
	// 2022-05-13 个人详情页:当用户在加锁的房间时,不显示进入房间的图标
	if g, ok := rooms[userId]; ok {
		gi, err := group_m.GetGroupInfo(model, g)
		if err != nil {
			return nil, err
		}
		if gi != nil && len(gi.Password) > 0 {
			rooms[userId] = ""
		}
	}

	groupPowerId, groupPowerName, err := groupPower_m.GetUserGroupPower(model, userId)
	if err != nil {
		return nil, err
	}
	powers := map[mysql.ID]uint64{userId: groupPowerId}
	powerNames := map[mysql.ID]string{userId: groupPowerName}
	groupPowerInfos, err := groupPower_m.MGetGroupPowerInfoMap(model, []mysql.ID{groupPowerId})
	groupPowerGrades, err := groupPower_m.MGetGroupPowerGrade(model, []mysql.ID{groupPowerId})
	groupPowerUsers, err := groupPower_m.MGetGroupPowerUsers(model, []mysql.ID{groupPowerId})
	var memberMax int
	grade := groupPowerGrades[groupPowerId].Grade
	if grade >= groupPower_e.GroupPowerGrade0 && grade <= groupPower_e.GroupPowerGradeMax {
		if grade == groupPower_e.GroupPowerGrade0 {
			memberMax = 300
		}
		if grade == groupPower_e.GroupPowerGrade1 {
			memberMax = 500
		}
		if grade == groupPower_e.GroupPowerGrade2 {
			memberMax = 800
		}
		if grade == groupPower_e.GroupPowerGrade3 {
			memberMax = 1200
		}
	}
	memberNum := len(groupPowerUsers[groupPowerId])
	if memberNum > memberMax {
		memberMax = memberNum
	}
	groupPowerMembers := [2]int{memberNum, memberMax} // 0->memberNum 1->memberLimit

	up := user_m.UserProperty{}
	rides, err := up.BatchGet(mysql.Db, []uint64{userId})
	if err != nil {
		return nil, err
	}

	//rp := res_m.ResProperty{}
	//properties, err := rp.GetAll(mysql.Db)
	properties, err := property_cv.GetPropertyAll(mysql.Db)
	if err != nil {
		return nil, err
	}
	ride := property_cv.CvProperty{
		Id:             rides[user.ID],
		PicUrl:         properties[rides[user.ID]].PicUrl,
		EffectUrl:      properties[rides[user.ID]].EffectUrl,
		SenderAvatar:   properties[rides[user.ID]].SenderAvatar,
		ReceiverAvatar: properties[rides[user.ID]].ReceiverAvatar,
		Using:          true,
	}
	noble, err := noble_m.FindActiveNoble(mysql.Db, userId)
	if err != nil {
		return nil, err
	}

	//判断是不是工会
	userTradeUnion, err := user_m.GetUserTradeUnion(myUserId)
	if err != nil {
		return nil, err
	}

	superManagerMap, err := user_m.GetSuperManagerMap([]uint64{userId})
	if err != nil {
		return nil, err
	}

	// 群组信息
	myGroups, err := group_m.FindGroupByOwner(model, userId)
	if err != nil {
		return nil, err
	}

	// 手机绑定信息
	// 第三方账号绑定信息
	phoneInfo := new(user_m.UserPhoneInfo)
	var thirdList []int8
	if userId == myUserId {
		thirdList = make([]int8, 0, 5)
		// 手机绑定信息
		bindInfo, err := user_m.GetUserBindInfoByUserId(model, userId)
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, err
		}
		if bindInfo != nil {
			if len(bindInfo.Phone) > 2 {
				phoneInfo.Phone = bindInfo.Phone[:2] + "****" + bindInfo.Phone[len(bindInfo.Phone)-2:]
			}
			phoneInfo.PhoneCountry = bindInfo.PhoneCountry
			phoneInfo.AreaCode = bindInfo.AreaCode
			phoneInfo.Icon = bindInfo.Icon
			thirdList = append(thirdList, 1)
		}
		// 第三方账号绑定信息
		thirdInfoList, err := user_m.GetUserOauthByUserId(model, userId, 0)
		if err != nil {
			return nil, err
		}
		if thirdInfoList != nil {
			for _, v := range thirdInfoList {
				thirdList = append(thirdList, v.ThirdPartyType)
			}
		}
	}
	// 国家管理员
	countryManager, err := country_m.GetCountryMgr(model, userId)
	if err != nil {
		return nil, err
	}
	var cvCountryManager *country_cv.CVCountryManager
	if countryManager != nil {
		cvCountryManager = &country_cv.CVCountryManager{
			Country: countryManager.Country,
			Role:    countryManager.Role,
		}
	}

	return userToDetailOne(model, &user, myUserId, userTradeUnion, likeN > 0, likeMe > 0,
		rel, isVip, expireTime, svip, headwear, ride, wealthUserScore.Grade, charmUserScore.Grade,
		activityUserScore.Grade, medals[userId], medalInfo[userId], rooms[userId], powers[userId], powerNames[userId], groupPowerInfos[groupPowerId], groupPowerGrades[groupPowerId], groupPowerMembers,
		noble, superManagerMap[userId], myGroups, phoneInfo, thirdList, cvCountryManager)
}

// 单用户版,简化参数
func userToDetailOne(model *domain.Model, user *user_m.User, myUserId mysql.ID, userTradeUnion *user_m.UserTradeUnion, isLike bool, likeMe bool, hvMap map[mysql.ID]Relation,
	isVip bool, vipExpireTime *int64, svip rpc.CvSvip, headwear *headwear_cv.CvHeadwear, ride property_cv.CvProperty, wealthGrade uint32, charmGrade uint32, activityGrade uint32,
	medals []uint32, medalInfo []medal_cv.CvMedal, room string, power uint64, powerName string, powerInfo groupPower_m.GroupPowerInfo, grade groupPower_m.GroupPowerGrade, members [2]int, noble *noble_m.UserNoble, isOfficialStaff bool,
	myGroups []group_m.GroupInfo, phoneInfo *user_m.UserPhoneInfo, thirdList []int8, countryManager *country_cv.CVCountryManager) (*CvUserDetail, error) {

	room, err := group_m.ToTxGroupId(model, room)
	if err != nil {
		model.Log.Warnf("ToTxGroupId failed for %s, err:%v", room, err)
		room = ""
	}

	cvUserDetail := &CvUserDetail{
		CvUserBase: CvUserBase{
			Id:              &user.ID,
			Avatar:          StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar)),
			DefaultAvatar:   &user.DefaultAvatar,
			ExternalId:      StrToString(&user.ExternalId),
			Nick:            StrNil(IfLogoutStr(IfLogout(user.LogoutTime), user.Code, user.Nick)),
			Description:     StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Description)),
			Sex:             TypeToUint8(&user.Sex),
			Country:         StrNil(user.Country),
			CountryIcon:     StrNil(user.CountryIcon),
			Code:            StrToString(&user.Code),
			IsPrettyCode:    user.IsPrettyCode(),
			IsVip:           isVip,
			IsOfficialStaff: isOfficialStaff,
			VipExpireTime:   vipExpireTime,
			Svip:            svip,
			Medals:          IfLogoutMedals(IfLogout(user.LogoutTime), []uint32{}, medals),
			MedalInfo:       IfLogoutMedalInfo(IfLogout(user.LogoutTime), []medal_cv.CvMedal{}, medalInfo),
			Headwear:        IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, headwear),
			Ride:            IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, ride),
		},
		IsPush:            TypeToUint8(&user.IsPush),
		IsLike:            &isLike,
		IsLikeMe:          &likeMe,
		WealthUserGrade:   wealthGrade,
		CharmUserGrade:    charmGrade,
		ActivityUserGrade: activityGrade,
		CurrentRoom:       room,
		MyGroupPower:      power,
		MyGroupPowerName:  powerName,
		GroupPower: GroupPower{
			Id:        power,
			Name:      powerInfo.Name,
			Icon:      powerInfo.Icon,
			Nameplate: powerInfo.Nameplate,
			Grade:     grade.Grade,
			MemberNum: mysql.Num(members[0]),
			MemberMax: mysql.Num(members[1]),
		},
		PhoneInfo:      phoneInfo,
		ThirdList:      thirdList,
		CountryManager: countryManager,
	}
	if noble != nil {
		cvUserDetail.Noble = noble_cv.CvNoble{
			Level:   noble.Level,
			EndTime: noble.EndTime.Unix(),
		}
	}

	//本人,计算,喜欢统计,钻石数量
	if user.ID == myUserId {
		cvUserDetail.IsShowAge = TypeToUint8((*mysql.Type)(&user.IsShowAge))
		cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday)

		//喜欢统计
		var userCount user_m.UserCount
		err := mysql.Db.Where(&user_m.UserCount{
			UserId: myUserId,
			Type:   user_e.CountTypeLikeMe,
		}).First(&userCount).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, myerr.WrapErr(err)
		}
		cvUserDetail.LikeCount = NumToUint32(&userCount.Num)

		//我喜欢统计
		var userILikeCount user_m.UserCount
		err = mysql.Db.Where(&user_m.UserCount{
			UserId: myUserId,
			Type:   user_e.CountTypeLike,
		}).First(&userILikeCount).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, myerr.WrapErr(err)
		}
		cvUserDetail.ILikeCount = NumToUint32(&userILikeCount.Num)

		//访问统计
		var visitCount int64
		err = mysql.Db.Model(&visit_m.UserVisit{}).Where(&visit_m.UserVisit{
			VisitUserId: myUserId,
		}).Count(&visitCount).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, myerr.WrapErr(err)
		}
		vc := uint32(visitCount)
		cvUserDetail.VisitCount = NumToUint32((*mysql.Num)(&vc))

		//钻石数量
		cvDiamond, err := diamond_cv.GetDiamond(myUserId)
		if err != nil {
			return nil, err
		}
		cvUserDetail.DiamondNum = cvDiamond.DiamondNum
		cvUserDetail.PinkDiamondNum = cvDiamond.PinkDiamondNum

		isAgent := user_m.IsAgent(myUserId)
		cvUserDetail.IsAgentMgr = &isAgent
	} else {
		//不是本人
		if user.IsShowAge == mysql.OPEN {
			cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday)
		}
	}

	if userTradeUnion == nil {
		isTradeUnionFlag := false
		cvUserDetail.IsTradeUnion = &isTradeUnionFlag
		cvUserDetail.IsTradeUnionMatchNotification = nil
	} else {
		isTradeUnionFlag := true
		cvUserDetail.IsTradeUnion = &isTradeUnionFlag
		isTradeUnionMatchNotificationFlag := userTradeUnion.MatchNotification == mysql.OPEN
		cvUserDetail.IsTradeUnionMatchNotification = &isTradeUnionMatchNotificationFlag
	}

	// 永恒之心的值
	hv, ok := hvMap[user.ID]
	if ok {
		cvUserDetail.HeartValue = hv.HeartValue
		cvUserDetail.HeartValueMax = hv.HeartValueMax
		cvUserDetail.MeetDays = hv.MeetDays
	} else {
		cvUserDetail.HeartValueMax = 0
	}

	// 拥有的群组id
	if len(myGroups) > 0 {
		cvUserDetail.GroupId = myGroups[0].TxGroupId
	}

	return cvUserDetail, nil
}

func GetUserBaseMap(userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]*CvUserBase, error) {
	userBases, err := GetUserBases(userIds, myUserId)
	if err != nil {
		return nil, err
	}
	//转换成map
	mapIdUser := map[mysql.ID]*CvUserBase{}
	for i := 0; i < len(userBases); i++ {
		mapIdUser[*userBases[i].Id] = userBases[i]
	}
	return mapIdUser, nil
}

//批量获取用户基本信息
func GetUserBases(userIds []mysql.ID, myUserId mysql.ID) ([]*CvUserBase, error) {
	if len(userIds) == 0 {
		return []*CvUserBase{}, nil
	}
	var users []user_m.User
	if err := mysql.Db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	vips, err := user_m.BatchGetVips(userIds)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}
	svips, err := rpc.MGetUserSvip(domain.CreateModelNil(), userIds)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}

	headwearMap, err := headwear_cv.BatchGetCvHeadwears(userIds)
	if err != nil {
		return nil, err
	}

	logger := mylogrus.MyLog.WithField("func", "GetUserBases")
	medals, err := user_m.BatchGetUserMedalMerge(logger, mysql.Db, userIds)
	if err != nil {
		return nil, err
	}

	medals, medalInfo, err := medal_cv.GetMedalInfoMap(mysql.Db, medals)
	if err != nil {
		return nil, err
	}

	up := user_m.UserProperty{}
	rides, err := up.BatchGet(mysql.Db, userIds)
	if err != nil {
		return nil, err
	}

	//rp := res_m.ResProperty{}
	//properties, err := rp.GetAll(mysql.Db)
	properties, err := property_cv.GetPropertyAll(mysql.Db)
	if err != nil {
		return nil, err
	}

	nobles, err := noble_m.BatchGetActiveNoble(mysql.Db, userIds)
	if err != nil {
		return nil, err
	}

	superManagerMap, err := user_m.GetSuperManagerMap(userIds)
	if err != nil {
		return nil, err
	}

	cvUserBases := []*CvUserBase{}
	for i := 0; i < len(users); i++ {
		user := users[i]
		invisible := IfLogout(user.LogoutTime)
		invisibleAvatar := ""
		invisibleNick := user.Code
		//for _, p := range svips[user.ID].Privileges {
		//	if p.Type == 17 && p.UserSwitch { // 神秘人特权
		//		invisible = true
		//		invisibleAvatar, invisibleNick = rpc.ReplaceSvipAvatarNick(invisibleAvatar, invisibleNick, svips[user.ID].Privileges)
		//	}
		//}
		cvUserBase := &CvUserBase{
			Id:              &user.ID,
			Avatar:          StrNil(IfLogoutStr(invisible, invisibleAvatar, user.Avatar)),
			DefaultAvatar:   &user.DefaultAvatar,
			ExternalId:      StrToString(&user.ExternalId),
			Nick:            StrNil(IfLogoutNick(invisible, invisibleNick, user.Nick)),
			Description:     StrNil(IfLogoutStr(invisible, "", user.Description)),
			Sex:             TypeToUint8(&user.Sex),
			Country:         StrNil(user.Country),
			CountryIcon:     StrNil(user.CountryIcon),
			Code:            StrToString(&user.Code),
			IsPrettyCode:    user.IsPrettyCode(),
			IsVip:           vips[user.ID] != nil,
			IsOfficialStaff: superManagerMap[user.ID],
			Medals:          IfLogoutMedals(invisible, []uint32{}, medals[user.ID]),
			MedalInfo:       IfLogoutMedalInfo(invisible, []medal_cv.CvMedal{}, medalInfo[user.ID]),
			Ride: IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, property_cv.CvProperty{
				Id:             rides[user.ID],
				PicUrl:         properties[rides[user.ID]].PicUrl,
				EffectUrl:      properties[rides[user.ID]].EffectUrl,
				Using:          true,
				SenderAvatar:   properties[rides[user.ID]].SenderAvatar,
				ReceiverAvatar: properties[rides[user.ID]].ReceiverAvatar,
			}),
			Noble: noble_cv.CvNoble{
				Level:   nobles[user.ID].Level,
				EndTime: nobles[user.ID].EndTime.Unix(),
			},
		}
		if cvUserBase.Noble.Level <= 0 {
			cvUserBase.Noble.EndTime = 0
		}
		//
		if headwear, flag := headwearMap[user.ID]; flag {
			cvUserBase.Headwear = IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, &headwear)
		}

		if user.ID == myUserId {
			cvUserBase.VipExpireTime = vips[user.ID]
			cvUserBase.IsShowAge = TypeToUint8(&user.IsShowAge)
			cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
		} else if user.IsShowAge == mysql.OPEN {
			cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
		}
		cvUserBase.Svip = svips[user.ID]

		cvUserBases = append(cvUserBases, cvUserBase)
	}
	return cvUserBases, nil
}

func BatchGetUserExtend(model *domain.Model, userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]CvUserExtend, error) {
	ub, err := GetUserBases(userIds, myUserId)
	if err != nil {
		return nil, err
	}
	wg, err := BatchGetWealthGrade(userIds)
	if err != nil {
		return nil, err
	}
	cg, err := BatchGetCharmGrade(userIds)
	if err != nil {
		return nil, err
	}
	ag, err := BatchGetActiveGrade(userIds)
	if err != nil {
		return nil, err
	}
	result := make(map[mysql.ID]CvUserExtend, 0)
	for _, i := range ub {
		result[*i.Id] = CvUserExtend{
			CvUserBase:  *i,
			WealthGrade: wg[*i.Id],
			CharmGrade:  cg[*i.Id],
			ActiveGrade: ag[*i.Id],
		}
	}
	return result, nil
}

func GetUserBase(userId mysql.ID, myUserId mysql.ID) (*CvUserBase, error) {
	var user user_m.User
	if err := mysql.Db.First(&user, userId).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}

	isVip, expireTime, err := user_m.IsVip(userId)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}

	cvHeadwear, err := headwear_cv.GetCvHeadwear(userId)
	if err != nil {
		return nil, err
	}

	logger := mylogrus.MyLog.WithField("func", "GetUserBase")
	medals, err := user_m.GetUserMedalMerge(logger, mysql.Db, userId)
	if err != nil {
		return nil, err
	}

	medals, medalInfo, err := getMedalInfo(mysql.Db, medals)
	if err != nil {
		return nil, err
	}

	up := user_m.UserProperty{}
	rides, err := up.BatchGet(mysql.Db, []uint64{userId})
	if err != nil {
		return nil, err
	}

	rp := res_m.ResProperty{}
	properties, err := rp.GetAll(mysql.Db)
	if err != nil {
		return nil, err
	}

	superManagerMap, err := user_m.GetSuperManagerMap([]uint64{userId})
	if err != nil {
		return nil, err
	}

	cvUserBase := CvUserBase{
		Id:              &user.ID,
		Avatar:          StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar)),
		DefaultAvatar:   &user.DefaultAvatar,
		ExternalId:      StrToString(&user.ExternalId),
		Nick:            StrNil(IfLogoutNick(IfLogout(user.LogoutTime), user.Code, user.Nick)),
		Description:     StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Description)),
		Sex:             TypeToUint8((*mysql.Type)(&user.Sex)),
		Country:         StrNil(user.Country),
		CountryIcon:     StrNil(user.CountryIcon),
		Code:            StrToString(&user.Code),
		IsPrettyCode:    user.IsPrettyCode(),
		IsVip:           isVip,
		IsOfficialStaff: superManagerMap[user.ID],
		Medals:          IfLogoutMedals(IfLogout(user.LogoutTime), []uint32{}, medals),
		MedalInfo:       IfLogoutMedalInfo(IfLogout(user.LogoutTime), []medal_cv.CvMedal{}, medalInfo),
		Headwear:        IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, cvHeadwear),
		Ride: IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, property_cv.CvProperty{
			Id:        rides[user.ID],
			PicUrl:    properties[rides[user.ID]].PicUrl,
			EffectUrl: properties[rides[user.ID]].EffectUrl,
		}),
	}

	noble, err := noble_m.FindActiveNoble(mysql.Db, userId)
	if err != nil {
		return nil, err
	}

	if noble != nil {
		cvUserBase.Noble = noble_cv.CvNoble{
			Level:   noble.Level,
			EndTime: noble.EndTime.Unix(),
		}
	}
	//本人
	if userId == myUserId {
		cvUserBase.VipExpireTime = expireTime
		cvUserBase.IsShowAge = TypeToUint8((*mysql.Type)(&user.IsShowAge))
		cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
		isAgent := user_m.IsAgent(myUserId)
		cvUserBase.IsAgentMgr = &isAgent
	} else if user.IsShowAge == mysql.OPEN {
		cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
	}

	//判断是不是工会
	userTradeUnion, err := user_m.GetUserTradeUnion(myUserId)
	if err != nil {
		return nil, err
	}
	if userTradeUnion == nil {
		isTradeUnionFlag := false
		cvUserBase.IsTradeUnion = &isTradeUnionFlag
		cvUserBase.IsTradeUnionMatchNotification = nil
	} else {
		isTradeUnionFlag := true
		cvUserBase.IsTradeUnion = &isTradeUnionFlag
		isTradeUnionMatchNotificationFlag := userTradeUnion.MatchNotification == mysql.OPEN
		cvUserBase.IsTradeUnionMatchNotification = &isTradeUnionMatchNotificationFlag
	}

	return &cvUserBase, nil
}

func getMedalInfo(db *gorm.DB, medals []uint32) ([]uint32, []medal_cv.CvMedal, error) {
	resMedals, err := res_m.MedalGetAllMap(db)
	if err != nil {
		return nil, nil, err
	}

	// 只选择合法的勋章
	validMedals := make([]uint32, 0)
	medalInfo := make([]medal_cv.CvMedal, 0)
	for _, i := range medals {
		if e, ok := resMedals[i]; ok {
			validMedals = append(validMedals, i)
			medalInfo = append(medalInfo, medal_cv.CvMedal{
				Id:        i,
				PicUrl:    e.PicUrl,
				EffectUrl: e.SvgaUrl,
			})
		}
	}
	return validMedals, medalInfo, nil
}