package group_cv

import (
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/utils"
	"hilo-group/_const/enum/game_e"
	"hilo-group/_const/enum/groupPower_e"
	"hilo-group/_const/enum/group_e"
	"hilo-group/_const/enum/online_e"
	"hilo-group/cv/billboard_cv"
	"hilo-group/cv/group_power_cv"
	"hilo-group/cv/medal_cv"
	"hilo-group/cv/user_cv"
	"hilo-group/domain/cache/res_c"
	"hilo-group/domain/cache/room_c"
	"hilo-group/domain/model/game_m"
	"hilo-group/domain/model/group_m"
	"hilo-group/domain/model/res_m"
	"hilo-group/domain/model/rocket_m"
	"hilo-group/domain/service/group_s"
	"hilo-group/myerr"
	"sort"
)

type GroupBasicInfo struct {
	Id            int64  `json:"id,omitempty"`
	GroupId       string `json:"groupId"`
	Name          string `json:"name"`
	Introduction  string `json:"introduction"`
	Notification  string `json:"notification"`
	FaceUrl       string `json:"faceUrl"`
	Owner_Account string `json:"ownerAccount"`
	CreateTime    int    `json:"createTime"`
	//LastInfoTime    int    `json:"last_info_time"`
	LastMsgTime     int     `json:"lastMsgTime"`
	NextMsgSeq      uint    `json:"nextMsgSeq"`
	MemberNum       uint    `json:"memberNum"`
	MaxMemberNum    uint    `json:"maxMemberNum"`
	ShutUpAllMember string  `json:"shutUpAllMember"`
	Code            string  `json:"code"`
	Password        *string `json:"password"`
	CountryIcon     string  `json:"countryIcon"`
	SupportLevel    uint8   `json:"supportLevel"` // 本周最高的扶持等级
	//1:5人 2:10人
	MicNumType int `json:"micNumType"`
	// N天内的进入用户数量(重复进入去重,实时)
	GroupInUserDuration int64                 `json:"groupInUserDuration"` // 群热度
	GroupMedals         []medal_cv.PicElement `json:"groupMedals"`         // 群勋章
	TouristMic          uint8                 `json:"touristMic"`          // 游客是否能上麦
	TouristSendMsg      uint8                 `json:"touristSendMsg"`      // 游客是否能发言
	TouristSendPic      uint8                 `json:"touristSendPic"`      // 游客是否能发图片
	MemberFee           uint64                `json:"memberFee"`           // 加入群组会员需要的黄钻
}

type MemberListInfo struct {
	Member_Account string `json:"memberAccount"`
	JoinTime       int    `json:"joinTime"`
	//MsgSeq          uint   `json:"msg_seq"`
	LastSendMsgTime int64 `json:"lastSendMsgTime"`
	//ShutUpUntil     int    `json:"shut_up_until"`
	// AppMemberDefinedData": [ // 群成员自定义字段 【暂时不用】
}

type GroupPower struct {
	Id        uint64                       `json:"id"`        // 群主所在的势力ID
	Name      string                       `json:"name"`      // 群主所在的势力的名称
	Nameplate string                       `json:"nameplate"` // 势力铭牌
	Grade     groupPower_e.GroupPowerGrade `json:"grade"`     // 等级
}

type GroupInfo struct {
	GroupBasicInfo

	// hilo业务
	EntryLevel          uint32     `json:"entryLevel"`          // obsolete
	HasOnMic            bool       `json:"hasOnMic"`            // 房间麦上是否有人
	GroupPowerId        uint64     `json:"groupPowerId"`        // 群主所在的势力ID
	GroupPowerName      string     `json:"groupPowerName"`      // 群主所在的势力的名称
	GroupPowerNameplate string     `json:"groupPowerNameplate"` // 势力铭牌
	GroupPower          GroupPower `json:"groupPower"`          // 势力信息

	// "AppDefinedData": 群组维度的自定义字段 【暂时不用】
	MemberList []MemberListInfo
}

type PopularGroupInfo struct {
	GroupInfo
	MicUsers      []user_cv.CvUserTiny `json:"micUsers"`            // 在麦上的用户,最多4个
	RoomUserCount uint                 `json:"roomUserCount"`       // 当前在房间的用户数
	MaxStage      *uint16              `json:"maxStage"`            // 今天爆过的最大的火箭
	GameTypes     []game_e.GameType    `json:"gameTypes,omitempty"` // 房间内正在进行的游戏 1:ludo 2:uno
}

// 最新的群组列表, 字段暂时应该跟popular一样
type LatestGroupInfo PopularGroupInfo

type TheirGroupsInfo struct {
	Total     uint              `json:"total"`
	OwnGroups []JoinedGroupInfo `json:"ownGroups"`
	Groups    []JoinedGroupInfo `json:"groups"`
}

type JoinedGroupInfo struct {
	PopularGroupInfo
	LastEnterTime int64 `json:"lastEnterTime"` // 最后一次进房间的时间
}

type JoinedGroupRsp struct {
	Total  uint              `json:"total"`
	Groups []JoinedGroupInfo `json:"groups"`
}

type RoleMemberInfo struct {
	user_cv.CvUserBase
	Role         group_e.GroupRoleType     `json:"role"`
	OnlineStatus online_e.OnlineStatusType `json:"onlineStatus"`
}

type MemberDetail struct {
	user_cv.CvUserExtend
	Role         group_e.GroupRoleType     `json:"role"`
	OnlineStatus online_e.OnlineStatusType `json:"onlineStatus"` // IM在线状态
	InRoom       bool                      `json:"inRoom"`       // 是否在房间内
}

type GroupVisitorsDetail struct {
	user_cv.CvGroupMember
	Role         group_e.GroupRoleType     `json:"role"`
	OnlineStatus online_e.OnlineStatusType `json:"onlineStatus"` // IM在线状态
	InRoom       bool                      `json:"inRoom"`       // 是否在房间内
}

type GroupDetail struct {
	GroupBasicInfo

	// hilo业务
	EntryLevel  uint32 `json:"entryLevel"` // obsolete
	MicOn       bool   `json:"micOn"`
	LoadHistory bool   `json:"loadHistory"`
	ThemeId     uint64 `json:"themeId"`
	ThemeUrl    string `json:"themeUrl"`
	// 1:官方 2:自定义
	ThemeType    uint8                               `json:"themeType"`
	Role         group_e.GroupRoleType               `json:"role"`
	MsgStatus    uint8                               `json:"msgStatus"`    // 消息提醒状态
	WelcomeText  string                              `json:"welcomeText"`  // 新成员入群欢迎语
	TotalConsume uint64                              `json:"totalConsume"` // 群内消费总额
	TopConsumers []billboard_cv.GroupTop3ConsumeUser `json:"topConsumers"` // 月最高消费三甲
	DiceNum      uint16                              `json:"diceNum"`      // 骰子游戏的数量
	DiceType     uint16                              `json:"diceType"`     // 骰子游戏的数字点数
	// "AppDefinedData": 群组维度的自定义字段 【暂时不用】
	RoleMembers []RoleMemberInfo      `json:"role_members"`
	Owner       *user_cv.CvUserDetail `json:"owner"` // 群主信息
}

type SimpleRoleInfo struct {
	ExternalId string                `json:"externalId"`
	Role       group_e.GroupRoleType `json:"role"`
}

type BannerElement struct {
	H5Url     string `json:"h5Url"`     // h5链接
	BannerUrl string `json:"bannerUrl"` // 图片地址
	ActionUrl string `json:"actionUrl"` // 统跳地址
}

type RoomInfo struct {
	GroupBasicInfo

	// hilo业务
	MicOn       bool   `json:"micOn"`
	LoadHistory bool   `json:"loadHistory"`
	ThemeId     uint64 `json:"themeId"`
	ThemeUrl    string `json:"themeUrl"`
	// 1:官方 2:自定义
	ThemeType       uint8                  `json:"themeType"`
	Role            group_e.GroupRoleType  `json:"role"`
	DiceNum         uint16                 `json:"diceNum"`  // 骰子游戏的数量
	DiceType        uint16                 `json:"diceType"` // 骰子游戏类型
	RoleMembers     []SimpleRoleInfo       `json:"roleMembers"`
	WelcomeText     string                 `json:"welcomeText"` // 新成员入群欢迎语
	Banners         []BannerElement        `json:"banners"`
	LuckyWheel      LuckyWheelState        `json:"luckyWheel"`
	TotalConsume    uint64                 `json:"totalConsume"`
	GameConfig      *game_m.GameConfig     `json:"gameConfig"`
	Owner           *user_cv.RoomInfoOwner `json:"owner"`
	EntryEffectType int                    `json:"entryEffectType"` // 进场特效类型 1: CP 2:神秘人 3:贵族 4:vip
	CpUserAvatar    string                 `json:"cpUserAvatar"`    // cp对象头像
	CpLevel         int                    `json:"cpLevel"`         // cp等级
}

type SupportPageDetail struct {
	GroupId             string               `json:"groupId"`
	CurrentConsume      uint64               `json:"currentConsume"`      // 当前周期的消费额(钻石)
	CurrentCount        uint32               `json:"currentCount"`        // 当前周期的消费人数
	LastConsume         uint64               `json:"lastConsume"`         // 上一个周期的消费额(钻石)
	LastCount           uint32               `json:"lastCount"`           // 上一个周期的消费人数
	SupportLevel        string               `json:"supportLevel"`        // 上一个周期(已结算)的支持等级
	SupporterLimit      uint32               `json:"supporterLimit"`      // 上一个周期(已结算)的支持者的上限
	CurrentSupportLevel string               `json:"currentSupportLevel"` // 当前的支持等级
	RemainSecond        int64                `json:"remainSecond"`        // 离下一次结算还有多少秒
	ProfitAllocator     user_cv.CvUserBase   `json:"profitAllocator"`     // 利益分配人,群主或由运营指定(官方群)
	Supporters          []user_cv.CvUserBase `json:"supporters"`          // 扶持管理员
	IsDispatched        bool                 `json:"isDispatched"`        // 奖励是否已经分配
}

type AwardResult struct {
	Success []string `json:"success"`
	Failed  []string `json:"failed"`
}

type GroupPowerTitle struct {
	Id             uint64               `json:"id"`
	Name           string               `json:"name"`
	GroupId        string               `json:"groupId"` // 势力的主群
	Avatar         string               `json:"avatar"`
	MemberNum      uint                 `json:"memberNum"`      // 成员人数
	Owner          user_cv.CvUserBase   `json:"owner"`          // 势力主
	Assistants     []user_cv.CvUserBase `json:"assistants"`     // 势力助手,目前就是主群的管理
	IsMyGroupPower bool                 `json:"isMyGroupPower"` // “我”是否属于这个势力
}

type RoomMedalInfo struct {
	Level      uint16 `json:"level"`
	PreviewUrl string `json:"previewUrl"`
	PicUrl     string `json:"picUrl"`
	Desc       string `json:"desc"`
}

type GroupChannelId struct {
	ChannelId  string `json:"channelId"`
	Token      string `json:"token"`
	AgoraId    uint32 `json:"agoraId"`
	MicNumType uint8  `json:"micNumType"`
	Provider   uint8  `json:"provider"` // 供应商 1.声网 2.腾讯trtc
}

//国籍视图
type CvCountry struct {
	//名字
	Name *string `json:"name"`
	//缩写
	ShortName *string `json:"shortName"`
	//图标地址
	Icon *string `json:"icon"`
	//code
	Code *string `json:"code"`
	// 手机区号
	AreaCode *string `json:"areaCode"`
	//手机号国家域名缩写
	AreaCodeName *string `json:"areaShortName"`
}

func BuildJoinedGroupInfo(myService *domain.Service, myUserId uint64, originGroupIds []string, pageSize, pageIndex int, _roomEnterTime ...map[string]int64) ([]JoinedGroupInfo, int, error) {
	model := domain.CreateModel(myService.CtxAndDb)

	groupInfo, err := group_m.BatchGetGroupInfo(model, originGroupIds)
	if err != nil {
		return nil, 0, err
	}
	var groupIds []string
	for _, groupId := range originGroupIds {
		if group, ok := groupInfo[groupId]; ok {
			if group.IsGameRoom == 0 {
				groupIds = append(groupIds, groupId)
			}
		}
	}
	if len(groupIds) <= 0 {
		return nil, 0, nil
	}

	// todo: 可以移到后面,减小查询范围,因为roomMicUserMap不影响排序
	roomMicUserMap, err := group_m.BatchGetAllMicUser(model, groupIds)
	if err != nil {
		return nil, 0, err
	}
	uids := make([]uint64, 0)
	micUsersMap := make(map[string][]uint64, 0)
	for _, i := range groupInfo {
		micUsersMap[i.ImGroupId] = make([]uint64, 0)

		if len(i.Password) <= 0 {
			// 密码群不显示麦上头像
			u := roomMicUserMap[i.ImGroupId]
			if len(u) >= 4 {
				micUsersMap[i.ImGroupId] = u[0:4]
			} else if len(u) > 0 {
				micUsersMap[i.ImGroupId] = u
			}
			uids = append(uids, micUsersMap[i.ImGroupId]...)
		}
	}

	uids = utils.UniqueSliceUInt64(uids)
	userTiny, err := user_cv.GetUserTinyMap(uids)
	if err != nil {
		return nil, 0, err
	}
	roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
	if err != nil {
		return nil, 0, err
	}

	countryInfo, err := res_c.GetCountryIconMap(model)
	if err != nil {
		return nil, 0, err
	}

	supportLevels, err := group_s.NewGroupService(model.MyContext).GetWeekMaxSupportLevelMap()
	if err != nil {
		return nil, 0, err
	}

	visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds)
	if err != nil {
		return nil, 0, err
	}

	roomEnterTime, err := room_c.GetUserRoomVisit(myUserId)
	if err != nil {
		return nil, 0, err
	}
	if len(_roomEnterTime) > 0 {
		roomEnterTime = _roomEnterTime[0]
	}
	//model.Log.Infof("BuildJoinedGroupInfo, roomEnterTime: %v", roomEnterTime)

	// 排序优先级V8.0版本
	sort.Slice(groupIds, func(i, j int) bool {
		gi := groupIds[i]
		gj := groupIds[j]
		return roomEnterTime[gi] > roomEnterTime[gj] ||
			roomEnterTime[gi] == roomEnterTime[gj] && visitCount[gj] > visitCount[gj] ||
			roomEnterTime[gi] == roomEnterTime[gj] && visitCount[gj] == visitCount[gj] && i >= j
	})

	result := make([]JoinedGroupInfo, 0)
	beginPos := pageSize * (pageIndex - 1)
	endPos := pageSize * pageIndex
	if beginPos < len(groupIds) {
		if endPos > len(groupIds) {
			endPos = len(groupIds)
		}

		groupIds = groupIds[beginPos:endPos]
		owners := make([]uint64, 0)
		for _, i := range groupIds {
			owners = append(owners, groupInfo[i].Owner)
		}
		powerIds, powerNames, powerNameplates, powerGrades, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
		if err != nil {
			return nil, 0, err
		}
		groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
		if err != nil {
			return nil, 0, err
		}
		resMedal, err := res_m.MedalGetAllMap(model.Db)
		if err != nil {
			return nil, 0, err
		}

		rr := rocket_m.RocketResult{}
		maxStageMap, err := rr.GetMaxStage(model.Db, groupIds)
		if err != nil {
			return nil, 0, err
		}
		// 正在进行的游戏
		games := game_m.GetNotEndGamesMap(model)

		for _, i := range groupIds {
			g := groupInfo[i]
			micUsers := make([]user_cv.CvUserTiny, 0)
			for _, j := range micUsersMap[i] {
				micUsers = append(micUsers, userTiny[j])
			}

			var maxStage *uint16 = nil
			if s, ok := maxStageMap[i]; ok {
				maxStage = &s
			}

			medals := make([]medal_cv.PicElement, 0)
			// 补上房间流水勋章
			var pe *medal_cv.PicElement
			_, pe, err = medal_cv.GetGroupConsumeMedal(model, i)
			if err != nil {
				model.Log.Infof("BuildJoinedGroupInfo: GetGroupConsumeMedal: %s", err.Error())
			} else if pe != nil {
				medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
			}
			// res_medal
			if m, ok := groupMedals[i]; ok {
				for _, j := range m {
					mId := uint32(j)
					if e, ok := resMedal[mId]; ok {
						medals = append(medals, medal_cv.PicElement{
							PicUrl: e.PicUrl,
						})
					}
				}
			}

			var password *string = nil
			if len(g.Password) > 0 && g.Owner != myUserId {
				emptyStr := ""
				password = &emptyStr
			}

			result = append(result, JoinedGroupInfo{
				PopularGroupInfo: PopularGroupInfo{
					GroupInfo: GroupInfo{
						GroupBasicInfo: GroupBasicInfo{
							GroupId:             g.TxGroupId,
							Name:                g.Name,
							Notification:        g.Notification,
							Introduction:        g.Introduction,
							FaceUrl:             g.FaceUrl,
							Code:                g.Code,
							CountryIcon:         countryInfo[g.Country],
							Password:            password,
							SupportLevel:        supportLevels[i],
							GroupInUserDuration: visitCount[i],
							MicNumType:          int(g.MicNumType),
							GroupMedals:         medals,
						},
						HasOnMic:            len(micUsers) > 0,
						GroupPowerId:        powerIds[g.Owner],
						GroupPowerName:      powerNames[g.Owner],
						GroupPowerNameplate: powerNameplates[g.Owner],
						GroupPower: GroupPower{
							Id:        powerIds[g.Owner],
							Name:      powerNames[g.Owner],
							Nameplate: powerNameplates[g.Owner],
							Grade:     powerGrades[g.Owner],
						},
					},
					MicUsers:      micUsers,
					RoomUserCount: uint(roomCount[i]),
					MaxStage:      maxStage,
					GameTypes:     games[g.TxGroupId],
				},
				LastEnterTime: roomEnterTime[i],
			})
		}
	}
	return result, len(groupInfo), nil
}

func BuildPopularGroupInfo(model *domain.Model, myUserId uint64, groupInfo []*group_m.GroupInfo) ([]*PopularGroupInfo, error) {
	groupIds := make([]string, 0, len(groupInfo))
	for _, v := range groupInfo {
		groupIds = append(groupIds, v.ImGroupId)
	}

	// roomMicUserMap不影响排序
	//roomMicUserMap, err := group_m.BatchGetAllMicUser(model, groupIds)
	//if err != nil {
	//	return nil, err
	//}
	//uids := make([]uint64, 0)
	//micUsersMap := make(map[string][]uint64, 0)
	//for _, v := range groupInfo {
	//	micUsersMap[v.ImGroupId] = make([]uint64, 0)
	//
	//	if len(v.Password) <= 0 {
	//		// 密码群不显示麦上头像
	//		u := roomMicUserMap[v.ImGroupId]
	//		if len(u) >= 4 {
	//			micUsersMap[v.ImGroupId] = u[0:4]
	//		} else if len(u) > 0 {
	//			micUsersMap[v.ImGroupId] = u
	//		}
	//		uids = append(uids, micUsersMap[v.ImGroupId]...)
	//	}
	//}

	//uids = utils.UniqueSliceUInt64(uids)
	//userTiny, err := user_cv.GetUserTinyMap(uids)
	//if err != nil {
	//	return nil, err
	//}
	roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
	if err != nil {
		return nil, err
	}

	countryInfo, err := res_c.GetCountryIconMap(model)
	if err != nil {
		return nil, err
	}

	supportLevels, err := group_s.NewGroupService(model.MyContext).GetWeekMaxSupportLevelMap()
	if err != nil {
		return nil, err
	}

	visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds)
	if err != nil {
		return nil, err
	}

	roomEnterTime, err := room_c.GetUserRoomVisit(myUserId)
	if err != nil {
		return nil, err
	}
	model.Log.Infof("BuildPopularGroupInfo, roomEnterTime: %v", roomEnterTime)

	// 排序优先级V8.0版本
	//sort.Slice(groupIds, func(i, j int) bool {
	//	gi := groupIds[i]
	//	gj := groupIds[j]
	//	return roomEnterTime[gi] > roomEnterTime[gj] ||
	//		roomEnterTime[gi] == roomEnterTime[gj] && visitCount[gj] > visitCount[gj] ||
	//		roomEnterTime[gi] == roomEnterTime[gj] && visitCount[gj] == visitCount[gj] && i >= j
	//})
	sort.Slice(groupIds, func(i, j int) bool {
		gj := groupIds[j]
		return visitCount[gj] > visitCount[gj]
	})

	result := make([]*PopularGroupInfo, 0)
	owners := make([]uint64, 0)
	for _, v := range groupInfo {
		owners = append(owners, v.Owner)
	}
	powerIds, powerNames, powerNameplates, powerGrades, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
	if err != nil {
		return nil, err
	}
	groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
	if err != nil {
		return nil, err
	}
	resMedal, err := res_m.MedalGetAllMap(model.Db)
	if err != nil {
		return nil, err
	}

	rr := rocket_m.RocketResult{}
	maxStageMap, err := rr.GetMaxStage(model.Db, groupIds)
	if err != nil {
		return nil, err
	}
	// 正在进行的游戏
	games := game_m.GetNotEndGamesMap(model)

	for _, v := range groupInfo {
		g := v
		i := v.ImGroupId
		//micUsers := make([]user_cv.CvUserTiny, 0)
		//for _, j := range micUsersMap[i] {
		//	micUsers = append(micUsers, userTiny[j])
		//}

		var maxStage *uint16 = nil
		if s, ok := maxStageMap[i]; ok {
			maxStage = &s
		}

		medals := make([]medal_cv.PicElement, 0)
		if m, ok := groupMedals[i]; ok {
			for _, j := range m {
				mId := uint32(j)
				if e, ok := resMedal[mId]; ok {
					medals = append(medals, medal_cv.PicElement{
						PicUrl: e.PicUrl,
					})
				}
			}
		}
		// 补上房间流水勋章
		var pe *medal_cv.PicElement
		_, pe, err = medal_cv.GetGroupConsumeMedal(model, i)
		if err != nil {
			model.Log.Infof("BuildPopularGroupInfo: GetGroupConsumeMedal: %s", err.Error())
		} else if pe != nil {
			medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
		}

		var password *string = nil
		if len(g.Password) > 0 && g.Owner != myUserId {
			emptyStr := ""
			password = &emptyStr
		}

		result = append(result, &PopularGroupInfo{
			GroupInfo: GroupInfo{
				GroupBasicInfo: GroupBasicInfo{
					GroupId:             g.TxGroupId,
					Name:                g.Name,
					Notification:        g.Notification,
					Introduction:        g.Introduction,
					FaceUrl:             g.FaceUrl,
					Code:                g.Code,
					CountryIcon:         countryInfo[g.Country],
					Password:            password,
					SupportLevel:        supportLevels[i],
					GroupInUserDuration: visitCount[i],
					MicNumType:          int(g.MicNumType),
					GroupMedals:         medals,
				},
				//HasOnMic:            len(micUsers) > 0,
				GroupPowerId:        powerIds[g.Owner],
				GroupPowerName:      powerNames[g.Owner],
				GroupPowerNameplate: powerNameplates[g.Owner],
				GroupPower: GroupPower{
					Id:        powerIds[g.Owner],
					Name:      powerNames[g.Owner],
					Nameplate: powerNameplates[g.Owner],
					Grade:     powerGrades[g.Owner],
				},
			},
			//MicUsers:      micUsers,
			RoomUserCount: uint(roomCount[i]),
			MaxStage:      maxStage,
			GameTypes:     games[g.TxGroupId],
		})
	}
	return result, nil
}

//检查群组中是否有有人在麦上,返回存在的Set[imGroupId]
func CheckMicHasUserByGroup(groupIds []string) (map[string]struct{}, error) {
	groupMap := map[string]struct{}{}
	for i := 0; i < len(groupIds); i++ {
		flag, err := group_m.CheckGroupMicHasUser(groupIds[i])
		if err != nil {
			return nil, myerr.WrapErr(err)
		}
		if flag {
			groupMap[groupIds[i]] = struct{}{}
		}
	}
	return groupMap, nil
}