package user_m

import (
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/resource/mysql"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"hilo-group/_const/enum/res_e"
	"hilo-group/domain/model/common"
	"hilo-group/domain/model/count_m"
	"hilo-group/domain/model/fruit_m"
	"hilo-group/domain/model/gift_m"
	"hilo-group/domain/model/luckybox_m"
	"hilo-group/domain/model/res_m"
	"hilo-group/domain/model/rocket_m"
	"hilo-group/myerr"
	"hilo-group/myerr/bizerr"
	"time"
)

//用户道具
type UserMedal struct {
	mysql.Entity
	*domain.Model `gorm:"-"`
	UserId        mysql.ID
	MedalId       uint32
	//MedalType     res_m2.ResMedalType
	//Scope         res_m2.ResMedalScope
	EndTime *time.Time
}

func GetUserMedalMerge(logger *logrus.Entry, db *gorm.DB, userId mysql.ID) ([]uint32, error) {
	// 缓存拿
	res, _ := common.GetUserMedalMergeCache(userId)
	if res != nil {
		return res, nil
	}

	// 数据库加载
	result, err := GetUserMedal(db, userId)
	if err != nil {
		return nil, err
	}
	logger.Infof("GetUserMedalMerge, user %d, %+v", userId, result)

	medalTypes, medalList, err := res_m.GetUserMedalLevelMap(db)
	if err != nil {
		return nil, err
	}
	//logger.Infof("GetUserMedalLevelMap, user %d, medalMap %+v", medalTypes)
	//logger.Infof("GetUserMedalLevelMap, user %d, medalList %+v", medalList)

	maxGrades := make(map[uint8]int, 0)
	maxMedalIds := make(map[uint8]uint32, 0)
	for _, m := range result {
		mt := medalTypes[uint64(m)]
		if mt > 0 {
			if r, ok := medalList[mt]; ok {
				for i, j := range r {
					if j == uint64(m) {
						if i+1 > maxGrades[mt] {
							maxGrades[mt] = i + 1
							maxMedalIds[mt] = m
							logger.Infof("maxGrade of %d set to %d, due to %d", mt, i+1, m)
						}
						break
					}
				}
			}
		}
	}
	logger.Infof("maxGrade %+v", maxGrades)
	logger.Infof("maxMedalIds %+v", maxMedalIds)

	mIds := result
	result = make([]uint32, 0)
	for _, m := range mIds {
		mt := medalTypes[uint64(m)]
		if mt == 0 || maxMedalIds[mt] == m {
			result = append(result, m)
		}
	}

	// 写入缓存
	common.SetUserMedalMergeCache(userId, result)
	return result, nil
}

func GetUserMedal(db *gorm.DB, userId mysql.ID) ([]uint32, error) {
	rows := make([]UserMedal, 0)
	if err := db.Model(&UserMedal{}).Where("user_id = ? AND (end_time >= NOW() or end_time is null)", userId).Find(&rows).Error; err != nil {
		return nil, err
	}
	result := make([]uint32, 0)
	for _, i := range rows {
		result = append(result, i.MedalId)
	}
	return result, nil
}

func BatchGetUserMedalMerge(logger *logrus.Entry, db *gorm.DB, userIds []mysql.ID) (map[uint64][]uint32, error) {
	result := make(map[uint64][]uint32, 0)
	for _, u := range userIds {
		a, err := GetUserMedalMerge(logger, db, u)
		if err != nil {
			return nil, err
		}
		result[u] = a
	}
	return result, nil
}

func BatchGetUserMedal(db *gorm.DB, userIds []mysql.ID) (map[uint64][]uint32, error) {
	rows := make([]UserMedal, 0)
	if err := db.Model(&UserMedal{}).Where("user_id IN ? and (end_time >= NOW() or end_time is null)", userIds).Find(&rows).Error; err != nil {
		return nil, err
	}
	result := make(map[uint64][]uint32, 0)
	for _, i := range rows {
		if _, ok := result[i.UserId]; !ok {
			result[i.UserId] = make([]uint32, 0)
		}
		result[i.UserId] = append(result[i.UserId], i.MedalId)
	}
	return result, nil
}

func (um *UserMedal) Create(db *gorm.DB, day int) error {
	err := db.Clauses(clause.OnConflict{
		DoUpdates: clause.Assignments(map[string]interface{}{
			"end_time": gorm.Expr("DATE_ADD(GREATEST(end_time,NOW()), INTERVAL ? DAY);", day)}),
	}).Create(um).Error
	// 删除勋章缓存, 延迟删除
	common.DelUserMedalMergeCacheDelay(um.UserId)
	return err
}

func (um *UserMedal) Delete(db *gorm.DB) error {
	err := db.Where(um).Delete(&UserMedal{}).Error
	// 删除勋章缓存
	common.DelUserMedalMergeCache(um.UserId)
	return err
}

func GetUserMedalThreshold(model *domain.Model, userId mysql.ID, resMedalId mysql.ID) (uint64, error) {
	resMedalObtain, err := res_m.ResMedalObtainGetByMedalId(model, resMedalId)
	if err != nil {
		return 0, err
	}
	if resMedalObtain == nil {
		return 0, myerr.NewSysErrorF("res_m.ResMedalObtainGetByMedalId nil resMedalId:%v", resMedalId)
	}
	if resMedalObtain.Type == res_e.WealthResMedalObtainType {
		wealthGrade, _, err := GetWealthGrade(model, userId)
		if err != nil {
			return 0, err
		} else {
			return uint64(wealthGrade), nil
		}
	} else if resMedalObtain.Type == res_e.CharmResMedalObtainType {
		charmGrade, _, err := GetCharmGrade(model, userId)
		if err != nil {
			return 0, err
		} else {
			return uint64(charmGrade), nil
		}
	} else if resMedalObtain.Type == res_e.GiftResMedalObtainType {
		sum, err := gift_m.SumSendGift(model, userId, resMedalObtain.ResGiftId)
		if err != nil {
			return 0, err
		}
		return uint64(sum), nil
	} else if resMedalObtain.Type == res_e.BoomRocketResMedalObtainType {
		s, err := rocket_m.GetUserTopCount(model.Db, userId)
		if err != nil {
			return 0, err
		}
		return uint64(s), nil
	} else if resMedalObtain.Type == res_e.ActityResMedalObtainType {
		wealthGrade, _, err := GetActityGrade(model, userId)
		if err != nil {
			return 0, err
		} else {
			return uint64(wealthGrade), nil
		}
	} else if resMedalObtain.Type == res_e.FruitKingResMedalObtainType {
		diamond, err := fruit_m.SumAwardAll(model.Db, userId)
		if err != nil {
			return 0, err
		} else {
			return uint64(diamond), nil
		}
	} else if resMedalObtain.Type == res_e.LuckyBoxKingResMedalObtainType {
		diamond, err := luckybox_m.GetSumLuckyboxDiamondV2(model, userId)
		if err != nil {
			return 0, err
		} else {
			return diamond, nil
		}
	} else if resMedalObtain.Type == res_e.VideoChatResMedalObtainType {
		videoSeconds, err := count_m.GetVideoChatTimeTotal(model, userId)
		if err != nil {
			return 0, err
		} else {
			return uint64(videoSeconds / 60), nil // min
		}
	} else {
		return 0, myerr.NewSysErrorF("GetUserMedalThreshold 类型错误 ResMedalType:%v", resMedalObtain.Type)
	}
}

//增加勋章
func (user *User) AddPublicMedal(resMedalId mysql.ID) (*UserMedal, error) {
	//判断是否已经拥有了该勋章
	var n int64
	if err := user.Db.Model(&UserMedal{}).Where(&UserMedal{
		UserId:  user.ID,
		MedalId: uint32(resMedalId),
	}).Count(&n).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	if n > 0 {
		return nil, myerr.NewWaringErrorF("用户 userId:%v, 已经获取了勋章 resMedalId:%v", user.ID, resMedalId)
	}
	resMedal, err := res_m.GetResMedalById(user.Model, resMedalId)
	if err != nil {
		return nil, err
	}
	//检查是否符合要求
	threshold, err := GetUserMedalThreshold(user.Model, user.ID, resMedalId)
	if err != nil {
		return nil, err
	}
	if threshold < uint64(resMedal.Threshold) {
		return nil, bizerr.UserMedalThresholdLimit
	}
	//
	return &UserMedal{
		Model:   user.Model,
		UserId:  user.ID,
		MedalId: uint32(resMedalId),
		//MedalType: resMedal.Type,
		//Scope:     resMedal.Scope,
		EndTime: nil,
	}, nil
}