package user_cv

import (
	"git.hilo.cn/hilo-common/_const/common"
	"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"
	"gorm.io/gorm"
	"hilo-user/_const/enum/country_e"
	"hilo-user/_const/enum/cp_e"
	"hilo-user/cv/headwear_cv"
	"hilo-user/cv/medal_cv"
	"hilo-user/cv/noble_cv"
	"hilo-user/cv/property_cv"
	"hilo-user/domain/model/noble_m"
	"hilo-user/domain/model/res_m"
	"hilo-user/domain/model/user_m"
	"hilo-user/myerr"
)

type UserTiny 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"` // 是否靓号
	Birthday     uint64 `json:"birthday"`
}

func UserToTiny(user user_m.User) *UserTiny {
	return &UserTiny{
		Id:           user.ID,
		ExternalId:   user.ExternalId,
		Avatar:       user.Avatar,
		Nick:         user.Nick,
		Sex:          user.Sex,
		Code:         user.Code,
		Country:      user.Country,
		CountryIcon:  user.CountryIcon,
		IsPrettyCode: user.IsPrettyCode(),
		Birthday:     user.Birthday,
	}
}

func UserTinyToCvTiny(user *user_m.UserTiny) *UserTiny {
	return &UserTiny{
		Id:           user.ID,
		ExternalId:   user.ExternalId,
		Avatar:       user.Avatar,
		Nick:         user.Nick,
		Sex:          user.Sex,
		Code:         user.Code,
		Country:      user.Country,
		CountryIcon:  user.CountryIcon,
		IsPrettyCode: user.IsPrettyCode,
	}
}

//用户基本信息
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"` // 是否靓号
	IsNew        bool    `json:"isNew"`        // 是否新用户
	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"`    // 勋章列表
	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     common.GroupRoleType    `json:"groupRole"` // 在群组的角色
}

//批量获取用户基本信息
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 {
		mylogrus.MyLog.Errorf("MGetUserSvip fail:%v", err)
		//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 := 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)
	propertiesArea := make(map[int]map[uint64]property_cv.CvProperty)
	for _, v := range []int{1, 2} {
		properties, err := GetPropertyAll(mysql.Db, v)
		if err != nil {
			return nil, err
		}
		propertiesArea[v] = properties
	}
	areaMap, err := user_m.GetUserAreaMap(domain.CreateModelNil(), userIds)
	if err != nil {
		return nil, err
	}

	nobles, err := noble_m.BatchGetActiveNoble(domain.CreateModelNil(), 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]
		properties := propertiesArea[areaMap[user.ID]]
		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(),
			IsNew:           user.IsNew(),
			IsVip:           vips[user.ID] != nil,
			IsOfficialStaff: superManagerMap[user.ID],
			Medals:          IfLogoutMedals(IfLogout(user.LogoutTime), []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
}

// 获取cp另一半基本信息
func GetUserBaseForCpMap(userIds []mysql.ID) (map[mysql.ID]*CvUserBase, error) {
	var res = make(map[mysql.ID]*CvUserBase)
	users, err := GetUserBasesForCp(userIds)
	if err != nil {
		return nil, err
	}
	for i, v := range users {
		if v.Id != nil {
			res[*v.Id] = users[i]
		}
	}
	return res, nil
}

// 批量获取cp另一半基本信息
func GetUserBasesForCp(userIds []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 {
		mylogrus.MyLog.Errorf("MGetUserSvip fail:%v", err)
	}

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

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

	var cvUserBases []*CvUserBase
	for i := 0; i < len(users); i++ {
		user := users[i]
		invisible := IfLogout(user.LogoutTime)
		invisibleAvatar := ""
		invisibleNick := user.Code
		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(),
			IsNew:         user.IsNew(),
			IsVip:         vips[user.ID] != nil,
			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)
		}
		cvUserBase.Svip = svips[user.ID]

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

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

	medalIds := make(map[uint64][]uint32)
	medalMap := make(map[uint64][]medal_cv.CvMedal, 0)

	// 只选择合法的勋章
	for u, i := range medals {
		medalIds[u] = make([]uint32, 0)
		medalMap[u] = make([]medal_cv.CvMedal, 0)

		for _, j := range i {
			if e, ok := resMedals[j]; ok {
				medalIds[u] = append(medalIds[u], j)
				medalMap[u] = append(medalMap[u], medal_cv.CvMedal{
					Id:        j,
					PicUrl:    e.PicUrl,
					EffectUrl: e.SvgaUrl,
				})
			}
		}
	}
	return medalIds, medalMap, nil
}

func GetPropertyAll(db *gorm.DB, area int) (map[uint64]property_cv.CvProperty, error) {
	rp := res_m.ResProperty{}
	properties, err := rp.GetAll(mysql.Db)
	if err != nil {
		return nil, err
	}

	//获取座驾头像
	propertyAvatarMap, err := (&res_m.ResPropertyAvatar{Area: area}).GetAll(mysql.Db)

	var userIds []uint64
	for _, value := range propertyAvatarMap {
		if value.SendUserId > 0 {
			userIds = append(userIds, value.SendUserId)
		}
		if value.ReceiverUserId > 0 {
			userIds = append(userIds, value.ReceiverUserId)
		}
	}
	//获取用户信息
	users := []user_m.User{}
	if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	userAvatarMap := map[mysql.ID]string{}
	for _, r := range users {
		userAvatarMap[r.ID] = r.Avatar
	}

	result := map[uint64]property_cv.CvProperty{}
	for _, r := range properties {

		var senderAvatar string = ""
		var receiverAvatar string = ""
		if propertyAvatar, flag := propertyAvatarMap[r.ID]; flag {
			if propertyAvatar.SendUserId > 0 {
				if avatar, flag := userAvatarMap[propertyAvatar.SendUserId]; flag {
					senderAvatar = avatar
				}
			}
			if propertyAvatar.ReceiverUserId > 0 {
				if avatar, flag := userAvatarMap[propertyAvatar.ReceiverUserId]; flag {
					receiverAvatar = avatar
				}
			}
		}

		result[r.ID] = property_cv.CvProperty{
			Id:             r.ID,
			PicUrl:         r.PicUrl,
			EffectUrl:      r.EffectUrl,
			SenderAvatar:   senderAvatar,
			ReceiverAvatar: receiverAvatar,
		}
	}
	return result, 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
}

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 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        rpc.CvGroupPowerInfo  `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    *CVCountryManager     `json:"countryManager,omitempty"` // 国家管理员
	Cp                *CvCp                 `json:"cp,omitempty"`             // cp信息
}

// cv国家管理人员
type CVCountryManager struct {
	Country string                   `json:"country"`                    // 国家name
	Role    country_e.CountryMgrRole `json:"role" swaggertype:"integer"` // 角色 1:国家管理员 2:国家助理
}

// cp信息
type CvCp struct {
	CpUserInfo      *CvUserBase   `json:"cpUserInfo"`      // cp用户信息
	CpLevel         CvCpLevel     `json:"cpLevel"`         // cp等级
	MyPrivilegeList []CvPrivilege `json:"myPrivilegeList"` // 等级特权
	CreatedUnix     int64         `json:"createdUnix"`     // cp创建时间
	CpDays          int           `json:"cpDays"`          // cp天数
}

// cp关系
type CvCpRelation struct {
	CpId         uint64 `json:"cpId"`
	UserId       uint64 `json:"userId"`
	CpUserId     uint64 `json:"cpUserId"`
	CpUserAvatar string `json:"cpUserAvatar,omitempty"`
}

// cp等级
type CvCpLevel struct {
	Level  cp_e.CpLevel `json:"level"`           // 等级 0:无称号 1:恋爱CP 2:甜蜜CP 3:忠诚CP 4:炽热CP 5:荣耀CP
	Points uint32       `json:"points"`          // CP值
	Title  string       `json:"title,omitempty"` // 称号翻译
}

// 特权信息
type CvPrivilege struct {
	Type cp_e.CpPrivilege `json:"type"` // 特权id 1:空间 2:横幅 3:等级勋章 4:证书 5:进场特效 6:头像头饰 7:动态资料卡 8:麦位特效
}