package group_s

import (
	"context"
	"git.hilo.cn/hilo-common/_const/enum/msg_e"
	"git.hilo.cn/hilo-common/_const/rediskey"
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/resource/mysql"
	"git.hilo.cn/hilo-common/resource/redisCli"
	"github.com/go-redis/redis/v8"
	"hilo-group/_const/enum/gift_e"
	"hilo-group/domain/event/group_ev"
	"hilo-group/domain/model/gift_m"
	"hilo-group/domain/model/group_m"
	"hilo-group/domain/model/msg_m"
	"hilo-group/domain/model/res_m"
	"hilo-group/domain/model/user_m"
	"hilo-group/myerr/bizerr"
	"strconv"
	"time"
)

// 群组支持名单过滤
func (s *GroupService) GroupSupportList(groupId string, uids []uint64) ([]uint64, []uint64, error) {
	if len(uids) <= 0 {
		return uids, nil, nil
	}

	result := make([]uint64, 0)
	out := make([]uint64, 0)

	err := s.svc.Transactional(func() error {
		model := domain.CreateModel(s.svc.CtxAndDb)

		// 1. 去掉非群管理者
		roles, _, err := group_m.GetRolesInGroup(model, groupId)
		if err != nil {
			return err
		}
		userIds := make([]uint64, 0)
		for _, i := range uids {
			if _, ok := roles[i]; ok {
				userIds = append(userIds, i)
			} else {
				out = append(out, i)
				model.Log.Infof("GroupSupportList: rule out %d, no role", i)
			}
		}

		// TODO: 去掉非群成员

		//(4)1个账户只能做1个群组的管理员(5)1个设备下只允许领取1个管理奖励
		_, _, period := group_m.GetLastSupportPeriod(time.Now())
		gsa := group_m.GroupSupportAwardMgr{Period: period}
		rows, err := gsa.Get(model.Db)
		if err != nil {
			return err
		}
		awards := make(map[uint64]struct{}, 0)
		for _, i := range rows {
			awards[i.UserId] = struct{}{}
		}

		uids = userIds
		userIds = make([]uint64, 0)
		m := make(map[uint64]uint64)
		for _, u := range uids {
			m, err := user_m.GetSameImeiMap(model, u)
			if err != nil {
				return err
			}

			passed := true
			for _, i := range m {
				if _, ok := awards[i]; ok {
					if i == u {
						passed = false
						model.Log.Infof("GroupSupportList: rule out %d, already awarded", i)
					} else {
						passed = false
						model.Log.Infof("GroupSupportList: rule out %d, imei awarded", i)
					}
				}
			}
			if passed == true {
				userIds = append(userIds, u)
			} else {
				out = append(out, u)
			}
		}
		model.Log.Infof("GroupSupportList: uids %v, map %v", uids, m)

		_, supportLevel, err := s.GetSupportLevel(groupId)
		if err != nil {
			return err
		}

		if uint32(len(userIds)) > supportLevel {
			model.Log.Infof("GroupSupportList: rule out %v, limit exeeded", userIds[supportLevel:])
			out = append(out, userIds[supportLevel:]...)
			userIds = userIds[0:supportLevel]
		}
		result = userIds
		return nil
	})

	if err == nil {
		return result, out, nil
	} else {
		return nil, nil, err
	}
}

func (s *GroupService) GetSupportLevel(groupId string) (uint64, uint32, error) {
	model := domain.CreateModel(s.svc.CtxAndDb)

	beginTime, endTime, _ := group_m.GetLastSupportPeriod(time.Now())

	g := gift_m.GiftOperate{SceneType: gift_e.GroupSceneType, SceneUid: groupId, Model: model}
	count, consume, err := g.GetConsumeByRange(beginTime, endTime)
	if err != nil {
		return 0, 0, err
	}

	rec, err := res_m.GetResGroupSupportBy(model, count, consume)
	if err != nil {
		return 0, 0, err
	}
	if rec != nil {
		return rec.ID, rec.MgrNum, nil
	}
	return 0, 0, nil
}

//群组支持奖励
func (s *GroupService) GroupSupportAward(groupId string, profitAllocator uint64, userIds []uint64, resId uint64, period string) error {
	return s.svc.Transactional(func() error {
		model := domain.CreateModel(s.svc.CtxAndDb)
		//
		groupInfo, err := group_m.GetGroupInfo(model, groupId)
		if groupInfo == nil {
			return bizerr.GroupNotFound
		}
		//发放奖励
		groupSupportAwardAdmin, groupSupportAwardMgrs, err := group_m.AddGroupSupportAward(model, groupId, profitAllocator, resId, userIds, period)
		if err != nil {
			return err
		}

		if err := groupSupportAwardAdmin.Persistent(); err != nil {
			return err
		}

		groupSupportEvent := group_ev.InitGroupSupportEvent(len(groupSupportAwardMgrs), groupInfo.Code)
		//数据持久化
		groupSupportEvent.AddAdmin(groupSupportAwardAdmin.ID, groupSupportAwardAdmin.UserId, groupSupportAwardAdmin.DiamondNum)
		for i, _ := range groupSupportAwardMgrs {
			if err := groupSupportAwardMgrs[i].Persistent(); err != nil {
				return err
			}
			groupSupportEvent.AddMgr(groupSupportAwardMgrs[i].ID, groupSupportAwardMgrs[i].UserId, groupSupportAwardMgrs[i].DiamondNum)
		}
		return group_ev.PublishGroupSupport(model, groupSupportEvent)
	})
}

func (s *GroupService) RenewGroupSupporter(groupId string, userIds []uint64) error {
	return s.svc.Transactional(func() error {
		model := domain.CreateModel(s.svc.CtxAndDb)
		gs := group_m.GroupSupporter{GroupId: groupId}
		if err := gs.Delete(model.Db); err != nil {
			return err
		}

		if len(userIds) > 0 {
			gs = group_m.GroupSupporter{GroupId: groupId}
			if err := gs.BatchSave(model.Db, userIds); err != nil {
				return err
			}
		}
		return nil
	})
}

func (s *GroupService) GroupSupportResult(time time.Time) error {
	model := domain.CreateModelContext(s.svc.MyContext)

	_, _, period := group_m.GetSupportLevelTime(time)
	// 群组扶持数值
	groupGradeMap, err := getGroupGradeMap(model, period)
	if err != nil {
		model.Log.Errorf("GroupSupportResult time:%v, err:%v", time, err)
		return err
	}

	model.Log.Infof("GroupSupportResult period:%s, len:%d, groupUidGadeMap:%v", period, len(groupGradeMap), groupGradeMap)
	// 房间访问人数
	roomVisitCount, err := GetAllRoomNonZeroVisitCount()
	if err != nil {
		model.Log.Errorf("GroupSupportResult err:%v", err)
		return err
	}

	// 入库群组扶持结果
	for g, grade := range groupGradeMap {
		r := group_m.InitGroupSupportResult(model, g, grade, period, roomVisitCount[g])
		r.SetOnDuplicateKeyIGNORE()
		if err = r.Persistent(); err != nil {
			model.Log.Errorf("GroupSupportResult InitGroupSupportResult r:%+v, err:%v", r, err)
		}
	}
	// 小助手通知
	AssistantNotification(model, groupGradeMap)
	return nil
}

func getGroupGradeMap(model *domain.Model, period string) (map[string]uint8, error) {
	// 配置
	gsConfig, err := res_m.GetResGroupSupportByValid(model)
	if err != nil {
		model.Log.Errorf("GroupSupportResult err:%v", err)
		return nil, err
	}

	// 群组扶持数值
	groupGradeMap := make(map[string]uint8, 0)
	//userNum := make(map[string]uint32, 0)

	// 流水
	keyDiamond := rediskey.GetGroupSupportConsumeSummary(period)
	var start int64
	count := int64(999)
	var zList []redis.Z
	// 一次取1000个处理
	for start == 0 || len(zList) > 0 {
		stop := start + count
		zList, err = model.RedisCluster.ZRangeWithScores(context.Background(), keyDiamond, start, stop).Result()
		if err != nil {
			model.Log.Errorf("GroupSupportResult err:%v", err)
			return nil, err
		}
		if len(zList) == 0 {
			break
		}
		for _, v := range zList {
			imGroupId := v.Member.(string)
			consume := mysql.Num(v.Score)
			// 支持者数量
			keySupportNum := rediskey.GetGroupSupportCountSupporter(period, imGroupId)
			supportNum, err := model.RedisCluster.SCard(context.Background(), keySupportNum).Result()
			if err != nil {
				model.Log.Errorf("GroupSupportResult key:%s, err:%v", keySupportNum, err)
				return nil, err
			}
			for j := len(gsConfig) - 1; j >= 0; j-- {
				if mysql.Num(supportNum) >= gsConfig[j].ContributeUserNum && consume >= gsConfig[j].ContributeDiamondNum {
					groupGradeMap[imGroupId] = gsConfig[j].Grade
					//userNum[imGroupId] = uint32(supportNum)
					break
				}
			}
		}
		start = stop + 1
	}
	return groupGradeMap, nil
}

func AssistantNotification(model *domain.Model, groupGradeMap map[string]uint8) {
	// 小助手通知
	for g, _ := range groupGradeMap {
		userId, err := group_m.GetProfitAllocator(model, g)
		if err != nil {
			model.Log.Errorf("GroupSupportResult msg GetProfitAllocator err:%v, groupUid:%v", err, g)
			continue
		}
		//推送
		user, err := user_m.GetUser(model, userId)
		if err != nil {
			model.Log.Infof("GroupSupportResult msg GetUser userId:=%v, err:=%v", userId, err)
			continue
		}
		record := msg_m.NewUserRecord(model, user.ID, msg_e.GroupSupportResult, "", 0, "", "", "", "", "")
		if err := record.Persistent(); err != nil {
			model.Log.Infof("GroupSupportResult msg record.Persistent() err:%v", err)
			continue
		}
		msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType)
	}
}

func GetAllRoomNonZeroVisitCount() (map[string]uint, error) {
	m, err := GetAllRoomVisitCount()
	if err != nil {
		return nil, err
	}
	result := make(map[string]uint, 0)
	for g, s := range m {
		if c, err := strconv.Atoi(s); err == nil && c > 0 {
			result[g] = uint(c)
		}
	}
	return result, nil
}

func GetAllRoomVisitCount() (map[string]string, error) {
	key := rediskey.GetPrefixRoomVisitCount()
	return redisCli.GetRedis().HGetAll(context.Background(), key).Result()
}