package gift_cv

import (
	"context"
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/resource/mysql"
	"git.hilo.cn/hilo-common/resource/redisCli"
	"git.hilo.cn/hilo-common/rpc"
	"git.hilo.cn/hilo-common/utils"
	redis2 "github.com/go-redis/redis/v8"
	"hilo-group/_const/enum/gift_e"
	"hilo-group/_const/redis_key"
	"hilo-group/domain/cache/group_c"
	"hilo-group/domain/model/gift_m"
	"hilo-group/domain/model/group_m"
	"hilo-group/domain/model/res_m"
	"hilo-group/myerr"
	"sort"
	"strconv"
	"time"
)

type GiftReceive struct {
	//礼物名字
	Name *string `json:"name"`
	//icon地址
	IconUrl *string `json:"iconUrl"`
	//svag地址
	SvagUrl *string `json:"svagUrl"`
	//music地址
	MusicUrl *string `json:"musicUrl"`
	//数量
	Num *uint32 `json:"num"`
	//总价值
	TotolPrice uint32 `json:"totolPrice"`
}

type GiftReceives []*GiftReceive

func (g GiftReceives) Less(i, j int) bool {
	return (g[i].TotolPrice) > (g[j].TotolPrice)
}

func (g GiftReceives) Len() int {
	return len(g)
}

func (g GiftReceives) Swap(i, j int) {
	g[i], g[j] = g[j], g[i]
}

func GetGiftReceive(UserId, reqUserId mysql.ID) ([]*GiftReceive, error) {
	if UserId != reqUserId {
		// 检查是否svip,是否打开了隐藏礼物墙
		// svip信息
		svipMap, err := rpc.MGetUserSvip(domain.CreateModelNil(), []uint64{UserId})
		if err != nil {
			return nil, err
		}
		if svip, ok := svipMap[UserId]; ok {
			for _, v := range svip.Privileges {
				if v.Type == 7 && v.CanSwitch && v.UserSwitch {
					return nil, nil
				}
			}
		}
	}

	giftCountUsers := []gift_m.GiftCountUser{}
	err := mysql.Db.Model(&gift_m.GiftCountUser{}).Where(&gift_m.GiftCountUser{
		UserId: UserId,
	}).Find(&giftCountUsers).Error
	if err != nil {
		return nil, myerr.WrapErr(err)
	}
	if len(giftCountUsers) == 0 {
		return []*GiftReceive{}, nil
	}
	//
	giftIds := []mysql.ID{}
	for i := 0; i < len(giftCountUsers); i++ {
		giftIds = append(giftIds, giftCountUsers[i].ResGiftId)
	}
	//
	gifts := []res_m.ResGift{}
	if err := mysql.Db.Model(&res_m.ResGift{}).Where("id in (?)", giftIds).Find(&gifts).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	//转换成map
	mapGift := map[mysql.ID]res_m.ResGift{}
	for i := 0; i < len(gifts); i++ {
		mapGift[gifts[i].GetID()] = gifts[i]
	}
	//
	giftReceives := []*GiftReceive{}
	for i := 0; i < len(giftCountUsers); i++ {
		gift := mapGift[giftCountUsers[i].ResGiftId]
		giftReceives = append(giftReceives, &GiftReceive{
			Name:       StrToString(&gift.Name),
			IconUrl:    StrToString(&gift.IconUrl),
			SvagUrl:    StrToString(&gift.SvagUrl),
			MusicUrl:   StrToString(&gift.MusicUrl),
			Num:        NumToUint32(&giftCountUsers[i].Num),
			TotolPrice: uint32(giftCountUsers[i].Num) * uint32(gift.DiamondNum),
		})
	}
	sort.Sort(GiftReceives(giftReceives))
	return giftReceives, nil
}

/**
 * 礼物操作
 **/
type GiftOperate struct {
	mysql.Entity
	*domain.Model      `gorm:"-"`
	ResGiftId          mysql.ID
	GiftN              mysql.Num
	SendUserId         mysql.ID
	ReceiveUserId      mysql.ID
	SendUserDiamond    mysql.Num
	ReceiveUserDiamond mysql.Num
	ReceiveUserBean    mysql.Num
	SceneType          gift_e.GiftOperateSceneType
	SceneUid           mysql.Str
}

/*func (g *GiftOperate) GetConsumeSummary(beginDate, endDate string) (map[string]uint64, error) {
	type summary struct {
		SceneUid string
		Sum      uint64
	}
	rows := make([]summary, 0)
	err := mysql.Db.Model(&GiftOperate{}).
		Select("scene_uid, SUM(send_user_diamond) AS sum").
		Where("scene_type = ? AND created_time >= ? AND DATE(created_time) <= ?", g.SceneType, beginDate, endDate).
		Group("scene_uid").Find(&rows).Error
	if err != nil {
		return nil, err
	}
	result := make(map[string]uint64, len(rows))
	for _, i := range rows {
		result[i.SceneUid] = i.Sum
	}
	return result, err
}*/

//
func (g *GiftOperate) GetConsumeSummary(now time.Time, dayWeekMonth string) (map[string]uint64, error) {
	key := ""
	if dayWeekMonth == "day" {
		key = redis_key.GetGiftOperateDay(now.Format(utils.COMPACT_DATE_FORMAT))
	} else if dayWeekMonth == "week" {
		key = redis_key.GetGiftOperateWeek(utils.GetMonday(now).Format(utils.COMPACT_DATE_FORMAT))
	} else if dayWeekMonth == "month" {
		key = redis_key.GetGiftOperateMonth(now.Format(utils.COMPACT_MONTH_FORMAT))
	}
	if key == "" {
		return nil, myerr.NewSysErrorF("GetConsumeSummary dayWeekMonth:%v, no find")
	}
	zs, err := redisCli.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, 29).Result()
	if err != nil {
		return nil, myerr.WrapErr(err)
	}
	result := make(map[string]uint64, len(zs))
	for _, r := range zs {
		result[r.Member.(string)] = uint64(r.Score)
	}
	return result, nil
}

func (g *GiftOperate) GetRangeConsumeSummary(beginTime, endTime time.Time, groupIds []string) (map[string]uint64, error) {
	result := make(map[string]uint64, len(groupIds))
	for i, _ := range groupIds {
		//移除过期的
		key := redis_key.GetGiftOperate1HourDurationGroupId(groupIds[i])
		if err := redisCli.GetRedis().ZRemRangeByScore(context.Background(), key, "0", strconv.FormatInt(beginTime.Unix(), 10)).Err(); err != nil {
			return nil, myerr.WrapErr(err)
		}
		//获取全部值,进行累加
		strs, err := redisCli.GetRedis().ZRange(context.Background(), key, 0, -1).Result()
		if err != nil {
			return nil, myerr.WrapErr(err)
		}
		//
		var total uint64 = 0
		for j, _ := range strs {
			score, err := strconv.ParseUint(strs[j], 10, 64)
			if err != nil {
				//异常则不退出
				g.Log.Errorf("GetRangeConsumeSummary ParseUint err:%v, str:%v", err, strs[j])
			} else {
				total = total + score
			}

		}
		result[groupIds[i]] = total
	}
	return result, nil
}

// 利用redis pipeline获取
func (g *GiftOperate) GetRangeConsumeSummaryV2(beginTime, endTime time.Time, groupIds []string) (map[string]uint64, error) {
	ctx := context.Background()
	result := make(map[string]uint64, len(groupIds))
	strss := make([]*redis2.StringSliceCmd, len(groupIds))
	_, err := redisCli.GetRedis().Pipelined(ctx, func(pipe redis2.Pipeliner) error {
		for i := range groupIds {
			//移除过期的
			key := redis_key.GetGiftOperate1HourDurationGroupId(groupIds[i])
			if err := pipe.ZRemRangeByScore(ctx, key, "0", strconv.FormatInt(beginTime.Unix(), 10)).Err(); err != nil {
				return myerr.WrapErr(err)
			}
			//获取全部值,进行累加
			strss[i] = pipe.ZRange(ctx, key, 0, -1)
		}
		return nil
	})
	for i, cmd := range strss {
		strs, err := cmd.Result()
		if err != nil {
			return nil, myerr.WrapErr(err)
		}
		var total uint64 = 0
		for j, _ := range strs {
			score, err := strconv.ParseUint(strs[j], 10, 64)
			if err != nil {
				//异常则不退出
				g.Log.Errorf("GetRangeConsumeSummary ParseUint err:%v, str:%v", err, strs[j])
			} else {
				total = total + score
			}

		}
		result[groupIds[i]] = total
	}
	return result, err
}

func GetGroupConsumeTotal(model *domain.Model, groupId string) (uint64, error) {
	sum, err := group_c.GetGroupConsume(groupId)
	if err == nil {
		model.Log.Debugf("redis.GetGroupConsume, groupId: %s, sum = %d", groupId, sum)
		return sum, nil
	}

	rmc := group_m.RoomMonthConsume{GroupId: groupId}
	result, err := rmc.GetTotalDiamond(model.Db)
	if err != nil {
		return 0, err
	}

	err = group_c.SetGroupConsume(groupId, result, time.Minute)
	model.Log.Debugf("redis.SetGroupConsume, groupId: %s, err:%v", groupId, err)

	return result, nil
}

func (g *GiftOperate) GetGroupConsumeSummary(groupId string, now time.Time, dayWeekMonth string) (map[uint64]uint64, error) {
	key := ""
	if dayWeekMonth == "day" {
		key = redis_key.GetGiftOperateGroupUidDay(groupId, now.Format(utils.COMPACT_DATE_FORMAT))
	} else if dayWeekMonth == "week" {
		key = redis_key.GetGiftOperateGroupUidWeek(groupId, utils.GetMonday(now).Format(utils.COMPACT_DATE_FORMAT))
	} else if dayWeekMonth == "month" {
		key = redis_key.GetGiftOperateGroupUidMonth(groupId, now.Format(utils.COMPACT_MONTH_FORMAT))
	}
	if key == "" {
		return nil, myerr.NewSysErrorF("GetConsumeSummary dayWeekMonth:%v, no find")
	}

	zs, err := redisCli.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, 29).Result()
	if err != nil {
		if err == redis2.Nil {
			return map[uint64]uint64{}, nil
		} else {
			return nil, myerr.WrapErr(err)
		}
	}
	sendUserMap := map[uint64]uint64{}
	for _, r := range zs {
		userId, err := strconv.ParseUint(r.Member.(string), 10, 64)
		if err != nil {
			return nil, myerr.WrapErr(err)
		}
		sendUserMap[userId] = uint64(r.Score)
	}
	return sendUserMap, nil
}

func (g *GiftOperate) GetGroupReceiveSummary(groupId string, now time.Time, dayWeekMonth string) (map[uint64]uint64, error) {
	key := ""
	if dayWeekMonth == "day" {
		key = redis_key.GetGiftOperateReceiveGroupUidDay(groupId, now.Format(utils.COMPACT_DATE_FORMAT))
	} else if dayWeekMonth == "week" {
		key = redis_key.GetGiftOperateReceiveGroupUidWeek(groupId, utils.GetMonday(now).Format(utils.COMPACT_DATE_FORMAT))
	} else if dayWeekMonth == "month" {
		key = redis_key.GetGiftOperateReceiveGroupUidMonth(groupId, now.Format(utils.COMPACT_MONTH_FORMAT))
	}
	if key == "" {
		return nil, myerr.NewSysErrorF("GetConsumeSummary dayWeekMonth:%v, no find")
	}

	zs, err := redisCli.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, 29).Result()
	if err != nil {
		if err == redis2.Nil {
			return map[uint64]uint64{}, nil
		} else {
			return nil, myerr.WrapErr(err)
		}
	}
	receiveUserMap := map[uint64]uint64{}
	for _, r := range zs {
		userId, err := strconv.ParseUint(r.Member.(string), 10, 64)
		if err != nil {
			return nil, myerr.WrapErr(err)
		}
		receiveUserMap[userId] = uint64(r.Score)
	}
	return receiveUserMap, nil
}

//type PendingInteraction struct {
//	user_cv.CvUserTiny
//	RecordType uint8 `json:"recordType"` // 记录类型:1、礼物,2、视频
//	SendTime   int64 `json:"sendTime"`   // 送礼物/视频的时间
//}

func StrToString(str *mysql.Str) *string {
	return (*string)(str)
}

func NumToUint32(num *mysql.Num) *uint32 {
	return (*uint32)(num)
}