package billboard_cv

import (
	"context"
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/resource/redisCli"
	"git.hilo.cn/hilo-common/utils"
	"hilo-group/_const/enum/gift_e"
	"hilo-group/_const/redis_key"
	"hilo-group/cv/gift_cv"
	"hilo-group/cv/user_cv"
	"sort"
	"strconv"
	"time"
)

//榜单中用户信息
type BillboardUserInfo struct {
	//用户基本信息
	UserBase user_cv.CvUserDetail `json:"userBase"`
	//数值
	Num uint64 `json:"num"`
}

//榜单中用户信息
type GroupTop3ConsumeUser struct {
	//用户基本信息
	UserBase user_cv.TopConsumersUser `json:"userBase"`
	//数值
	Num uint64 `json:"num"`
}

func GetGroupTop3Consume(model *domain.Model, groupId string, myUserId uint64) ([]GroupTop3ConsumeUser, error) {
	now := time.Now()
	period := now.Format(utils.COMPACT_MONTH_FORMAT)
	data, err := getGroupTop3Consume(period, groupId)

	result := make([]BillboardUserInfo, 0)
	failed := false
	if err != nil {
		failed = true
	} else {
		model.Log.Infof("GetGroupTop3Consume, from redis: %+v", data)
		ts, err := strconv.ParseUint(data["timestamp"], 10, 64)
		if err != nil {
			failed = true
		} else {
			// 超过5分钟就认为是过期数据
			if now.Unix()-int64(ts) >= 60*5 {
				failed = true
			}
		}
	}

	if failed {
		result, err := BuildMonthlyGroupConsumeBillboard(groupId, 3, myUserId)
		if err != nil {
			return nil, err
		}
		diamonds := make(map[uint64]uint64, 0)
		for _, i := range result {
			if i.UserBase.Id != nil {
				diamonds[*i.UserBase.Id] = i.Num
			}
		}
		model.Log.Infof("GetGroupTop3Consume, DB: %+v", diamonds)
		ret, err := saveGroupTop3Consume(period, groupId, diamonds)

		model.Log.Infof("GetGroupTop3Consume SAVE ret = %d, err: %v", ret, err)

		list := make([]GroupTop3ConsumeUser, 0, len(result))
		for _, v := range result {
			list = append(list, GroupTop3ConsumeUser{
				UserBase: user_cv.TopConsumersUser{Id: v.UserBase.Id, Avatar: v.UserBase.Avatar, ExternalId: v.UserBase.ExternalId, Nick: v.UserBase.Nick},
			})
		}

		return list, nil
	}

	userIds := make([]uint64, 0)
	diamonds := make(map[uint64]uint64, 0)
	for k, v := range data {
		if uid, err := strconv.ParseUint(k, 10, 64); err == nil {
			if num, err := strconv.ParseInt(v, 10, 64); err == nil {
				userIds = append(userIds, uid)
				diamonds[uid] = uint64(num)
			}
		}
	}

	users, err := user_cv.GetUserDetailMap(userIds, myUserId)
	if err != nil {
		return nil, err
	}

	for _, i := range userIds {
		if users[i] != nil {
			result = append(result, BillboardUserInfo{
				UserBase: *users[i],
				Num:      diamonds[i],
			})
		}
	}

	list := make([]GroupTop3ConsumeUser, 0, len(result))
	for _, v := range result {
		list = append(list, GroupTop3ConsumeUser{
			UserBase: user_cv.TopConsumersUser{Id: v.UserBase.Id, Avatar: v.UserBase.Avatar, ExternalId: v.UserBase.ExternalId, Nick: v.UserBase.Nick},
		})
	}

	return list, nil
}

func getGroupTop3Consume(period string, groupId string) (map[string]string, error) {
	key := redis_key.GetGroupTop3ConsumeKey(period, groupId)
	return redisCli.GetRedis().HGetAll(context.Background(), key).Result()
}

func saveGroupTop3Consume(period string, groupId string, diamonds map[uint64]uint64) (int64, error) {
	values := make(map[string]interface{}, 0)
	for p, d := range diamonds {
		if d > 0 {
			values[strconv.FormatUint(p, 10)] = d
		}
	}
	if len(values) <= 0 {
		return 0, nil
	}

	values["timestamp"] = time.Now().Unix()
	key := redis_key.GetGroupTop3ConsumeKey(period, groupId)
	ret, err := redisCli.GetRedis().HSet(context.Background(), key, values).Result()

	if err == nil {
		// 设置一个TTL保险一些 TODO: 可以优化,保证数据总是有的
		redisCli.GetRedis().Expire(context.Background(), key, time.Minute*15)
	}
	return ret, err
}

func BuildMonthlyGroupConsumeBillboard(groupId string, length int, myUserId uint64) ([]BillboardUserInfo, error) {
	//now := time.Now()
	//endDate := now.Format(common.DATE_FORMAT)
	//beginDate := common.GetFirstDay(now).Format(common.DATE_FORMAT)
	return BuildGroupConsumeBillboard(groupId, time.Now(), length, myUserId, "month")
}

func BuildGroupConsumeBillboard(groupId string, endDate time.Time, length int, myUserId uint64, dayWeekMonth string) ([]BillboardUserInfo, error) {
	g := gift_cv.GiftOperate{SceneType: gift_e.GroupSceneType}
	scores, err := g.GetGroupConsumeSummary(groupId, endDate, dayWeekMonth)
	if err != nil {
		return nil, err
	}
	userIds := make([]uint64, 0)
	for k, _ := range scores {
		userIds = append(userIds, k)
	}
	sort.SliceStable(userIds, func(i, j int) bool {
		return scores[userIds[i]] > scores[userIds[j]]
	})
	if length > len(userIds) {
		length = len(userIds)
	}
	userIds = userIds[0:length]
	users, err := user_cv.GetUserDetailMap(userIds, myUserId)
	if err != nil {
		return nil, err
	}

	result := make([]BillboardUserInfo, 0)
	for _, i := range userIds {
		if users[i] != nil {
			result = append(result, BillboardUserInfo{
				UserBase: *users[i],
				Num:      scores[i],
			})
		}
	}
	return result, nil
}