package diamond_cv

import (
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/resource/mysql"
	. "git.hilo.cn/hilo-common/utils"
	"gorm.io/gorm"
	"hilo-group/_const/enum/diamond_e"
	"hilo-group/domain/model/bean_m"
	"hilo-group/domain/model/diamond_m"
	"hilo-group/myerr"
	"strconv"
)

type CvDiamond struct {
	//钻石数量
	DiamondNum *uint32 `json:"diamondNum"`
	//粉钻数量
	PinkDiamondNum *uint32 `json:"pinkDiamondNum"`
}

type CvDiamondBean struct {
	//钻石数量
	DiamondNum uint32 `json:"diamondNum"`
	//豆子数量
	BeanNum string `json:"beanNum"`
}

func GetDiamondBean(userId mysql.ID) (*CvDiamondBean, error) {
	var diamondAccount diamond_m.DiamondAccount
	err := mysql.Db.Where(&diamond_m.DiamondAccount{
		UserId: userId,
	}).First(&diamondAccount).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			diamondAccount = diamond_m.DiamondAccount{
				DiamondNum: 0,
			}
		}
		return nil, err
	}

	var beanAccount bean_m.BeanAccount
	err = mysql.Db.Where(&bean_m.BeanAccount{
		UserId: userId,
	}).First(&beanAccount).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			beanAccount = bean_m.BeanAccount{
				BeanNum: 0,
			}
		}
	}
	return &CvDiamondBean{DiamondNum: diamondAccount.DiamondNum, BeanNum: strconv.FormatFloat(float64(beanAccount.BeanNum)/100, 'f', 2, 64)}, nil
}

type CvDiamondDetail struct {
	//1:增加 2:减少
	AddReduce *uint8 `json:"addReduce"`
	//6:注册 3:建立融云会话 4:购买钻石 1:发送礼物 5:接受礼物 2:匹配条件
	OperateType *uint8 `json:"operateType"`
	//钻石的数量
	DiamondNum *uint32 `json:"diamondNum"`
	//创建时间
	CreatedTime *int64 `json:"createdTime"`
}

func GetDiamond(userId mysql.ID) (*CvDiamond, error) {
	var diamondAccount diamond_m.DiamondAccount
	err := mysql.Db.Where(&diamond_m.DiamondAccount{
		UserId: userId,
	}).First(&diamondAccount).Error
	if err != nil {
		return nil, err
	}
	return &CvDiamond{DiamondNum: NumToUint32(&diamondAccount.DiamondNum), PinkDiamondNum: NumToUint32(&diamondAccount.PinkDiamondNum)}, nil
}

func GetDiamondBalances(userIds []mysql.ID) (map[mysql.ID]mysql.Num, error) {
	result := make(map[mysql.ID]mysql.Num, len(userIds))
	data := make([]diamond_m.DiamondAccount, 0)
	err := mysql.Db.Where("user_id IN ?", userIds).Find(&data).Error
	if err != nil {
		return nil, err
	}
	for _, i := range data {
		result[i.UserId] = i.DiamondNum
	}
	return result, nil
}

//充值记录
func GetDiamondBuyList(userId mysql.ID, pageSize int, pageIndex int) ([]*CvDiamondDetail, error) {
	var diamondAccountDetails []diamond_m.DiamondAccountDetail
	if err := mysql.Db.Model(&diamond_m.DiamondAccountDetail{}).
		Where("user_id = ? AND operate_type in (?)", userId, []uint8{diamond_e.BuyDiamond, diamond_e.DealerTransfer, diamond_e.Checkout, diamond_e.PayerMax, diamond_e.Paypal}).
		Order("id desc").Limit(pageSize).Offset((pageIndex - 1) * pageSize).Find(&diamondAccountDetails).Error; err != nil {
		return nil, err
	}
	var cvDiamondDetails []*CvDiamondDetail

	for i := 0; i < len(diamondAccountDetails); i++ {
		unixTime := diamondAccountDetails[i].CreatedTime.Unix()
		cvDiamondDetails = append(cvDiamondDetails, &CvDiamondDetail{
			AddReduce:   TypeToUint8(&diamondAccountDetails[i].AddReduce),
			OperateType: TypeToUint8(&diamondAccountDetails[i].OperateType),
			DiamondNum:  NumToUint32(&diamondAccountDetails[i].Num),
			CreatedTime: &unixTime,
		})
	}
	return cvDiamondDetails, nil
}

//钻石明细,不包括充值
func GetDiamondDetailList(model *domain.Model, userId mysql.ID, pageSize int, pageIndex int) ([]*CvDiamondDetail, error) {
	diamondAccountDetails := make([]*diamond_m.DiamondAccountDetail, 0)
	offset := (pageIndex - 1) * pageSize
	optList := []int{int(diamond_e.BuyDiamond), int(diamond_e.DealerTransfer), int(diamond_e.Checkout), int(diamond_e.PayerMax)}
	details := make([]*diamond_m.DiamondAccountDetail, 0)
	if offset == 0 { // 首页请求数据,获取 pageSize*3 条过滤返回
		sql := "select * from diamond_account_detail where user_id = ? order by id desc limit ?"
		if err := mysql.Db.WithContext(model).Raw(sql, userId, pageSize*3).Find(&details).Error; err != nil {
			return nil, myerr.WrapErr(err)
		}
		notInMap := make(map[int]bool)
		for _, v := range optList {
			notInMap[v] = true
		}
		for _, v := range details {
			if _, ok := notInMap[int(v.OperateType)]; !ok {
				diamondAccountDetails = append(diamondAccountDetails, v)
			}
		}
		if len(diamondAccountDetails) > pageSize {
			diamondAccountDetails = diamondAccountDetails[:pageSize]
		}
	}
	// 非首页,或者首页没取满 pageSize 条
	if offset > 0 || (len(details) == pageSize*3 && len(diamondAccountDetails) < pageSize) {
		diamondAccountDetails = make([]*diamond_m.DiamondAccountDetail, 0)
		sql := "select * from diamond_account_detail where user_id = ? and operate_type not in (?) order by id desc limit ?,?"
		if err := mysql.Db.WithContext(model).Raw(sql, userId, optList, offset, pageSize).
			Find(&diamondAccountDetails).Error; err != nil {
			return nil, myerr.WrapErr(err)
		}
	}

	//if err := mysql.Db.Table("diamond_account_detail FORCE INDEX(Index_1)").
	//	Where("user_id = ? AND operate_type not in (?)", userId,
	//		[]int{int(diamond_m2.BuyDiamond), int(diamond_m2.DealerTransfer), int(diamond_m2.Checkout), int(diamond_m2.PayerMax)}).
	//	Order("id desc").Limit(pageSize).Offset((pageIndex - 1) * pageSize).Find(&diamondAccountDetails).Error; err != nil {
	//	return nil, myerr.WrapErr(err)
	//}
	cvDiamondDetails := []*CvDiamondDetail{}
	for i := 0; i < len(diamondAccountDetails); i++ {
		unixTime := diamondAccountDetails[i].CreatedTime.Unix()
		cvDiamondDetails = append(cvDiamondDetails, &CvDiamondDetail{
			AddReduce:   TypeToUint8(&diamondAccountDetails[i].AddReduce),
			OperateType: TypeToUint8(&diamondAccountDetails[i].OperateType),
			DiamondNum:  NumToUint32(&diamondAccountDetails[i].Num),
			CreatedTime: &unixTime,
		})
	}
	return cvDiamondDetails, nil
}

//粉钻流水,包含充值
func GetPinkDiamondDetailList(userId mysql.ID, pageSize int, pageIndex int) ([]*CvDiamondDetail, error) {
	var diamondAccountDetails []diamond_m.DiamondPinkAccountDetail
	if err := mysql.Db.Model(&diamond_m.DiamondPinkAccountDetail{}).
		Where("user_id = ?", userId).
		Order("id desc").Limit(pageSize).Offset((pageIndex - 1) * pageSize).Find(&diamondAccountDetails).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	var cvDiamondDetails []*CvDiamondDetail
	for i := 0; i < len(diamondAccountDetails); i++ {
		unixTime := diamondAccountDetails[i].CreatedTime.Unix()
		cvDiamondDetails = append(cvDiamondDetails, &CvDiamondDetail{
			AddReduce:   TypeToUint8(&diamondAccountDetails[i].AddReduce),
			OperateType: TypeToUint8(&diamondAccountDetails[i].OperateType),
			DiamondNum:  NumToUint32(&diamondAccountDetails[i].Num),
			CreatedTime: &unixTime,
		})
	}
	return cvDiamondDetails, nil
}