package diamond_m

import (
	"fmt"
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/mylogrus"
	"git.hilo.cn/hilo-common/resource/mysql"
	"git.hilo.cn/hilo-common/utils"
	"gorm.io/gorm"
	"hilo-group/_const/enum/diamond_e"
	"hilo-group/myerr"
	"hilo-group/myerr/bizerr"
	"strconv"
	"time"
)

type DiamondAccount struct {
	mysql.Entity
	*domain.Model  `gorm:"-"`
	UserId         mysql.ID
	DiamondNum     mysql.Num
	PinkDiamondNum mysql.Num
	Status         diamond_e.StatusAccount
}

//账号详情
type DiamondAccountDetail struct {
	mysql.Entity
	*domain.Model    `gorm:"-"`
	UserId           mysql.ID
	DiamondAccountId mysql.ID
	OperateId        mysql.ID
	OperateType      diamond_e.OperateType
	OriginId         mysql.ID
	AddReduce        mysql.AddReduce
	Num              mysql.Num
	Remark           mysql.Str
	BefNum           mysql.Num
	AftNum           mysql.Num
	diamondAccount   *DiamondAccount `gorm:"-"`
}

func (DiamondAccountDetail) TableName() string {
	month := time.Now().Format("200601")
	return fmt.Sprintf("diamond_account_detail_%s", month)
}

// 粉钻详情
type DiamondPinkAccountDetail struct {
	mysql.Entity
	*domain.Model    `gorm:"-"`
	UserId           mysql.ID
	DiamondAccountId mysql.ID
	OperateId        mysql.ID
	OperateType      diamond_e.OperateType
	OriginId         mysql.ID
	AddReduce        mysql.AddReduce
	Num              mysql.Num
	Remark           mysql.Str
	BefNum           mysql.Num
	AftNum           mysql.Num
	diamondAccount   *DiamondAccount `gorm:"-"`
}

//通过userId获取帐号
func GetDiamondAccountByUserId(model *domain.Model, userId mysql.ID) (*DiamondAccount, error) {
	var diamondAccount DiamondAccount
	if err := model.Db.WithContext(model).Where(&DiamondAccount{
		UserId: userId,
	}).First(&diamondAccount).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}
	diamondAccount.Model = model
	return &diamondAccount, nil
}

//账号操作配置
type DiamondOperateSet struct {
	mysql.Entity
	*domain.Model `gorm:"-"`
	DiamondNum    mysql.NumAll
	FrequencyNum  mysql.NumAll
	FrequencyDay  mysql.NumAll
	DiamondMaxNum mysql.NumAll
	AddReduce     mysql.AddReduce
	Type          diamond_e.OperateType
	Name          mysql.Str
	Status        mysql.UserYesNo
	DiamondType   diamond_e.OperateType
}

//匹配条件扣费
func (diamondAccount *DiamondAccount) ChangeDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
	return diamondAccount.addDiamondAccountDetail(operateType, originId, diamondNum)
}

//钻石操作记录,
func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
	var diamondOperateSet DiamondOperateSet
	var err error
	if err = diamondAccount.Db.Where(&DiamondOperateSet{
		Type:        operateType,
		Status:      mysql.USER,
		DiamondType: 1, // 1:黄钻 2:粉钻
	}).First(&diamondOperateSet).Error; err != nil {
		return nil, myerr.WrapErr(err)
	}

	//判断是增加,账号是否被冻结
	if diamondAccount.Status == diamond_e.Frozen && diamondOperateSet.AddReduce == mysql.REDUCE {
		return nil, bizerr.DiamondAccountFrozen
	}

	//无限,检查次数
	var count int64
	if diamondOperateSet.FrequencyDay == -1 {
		if diamondOperateSet.FrequencyNum != -1 {
			diamondAccount.DB().Table(DiamondAccountDetail{}.TableName()).Where(&DiamondAccountDetail{
				UserId:      diamondAccount.UserId,
				OperateType: operateType,
			}).Count(&count)
			if count >= int64(diamondOperateSet.FrequencyNum) {
				return nil, bizerr.DiamondFrequency
				//return nil, myerr.NewSysError("钻石操作次数多大, userId:" + mysql.IdToStr(diamondAccount.UserId) + " diamondOperateSetId" + mysql.IdToStr(diamondOperateSet.ID))
			}
		}
	} else if diamondOperateSet.FrequencyDay == 1 {
		beginTime, err := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local)
		if err != nil {
			return nil, myerr.WrapErr(err)
		}
		//一天的次数
		diamondAccount.DB().Table(DiamondAccountDetail{}.TableName()).Where(&DiamondAccountDetail{
			UserId:      diamondAccount.UserId,
			OperateType: operateType,
		}).Where("created_time >= ? ", beginTime).Count(&count)
		if count >= int64(diamondOperateSet.FrequencyNum) {
			return nil, bizerr.DiamondFrequency
		}
		//终极拦截,利用
		diamondAccount.SetCheckUpdateCondition(" EXISTS (SELECT * from (SELECT COUNT(1)  as n from " + DiamondAccountDetail{}.TableName() + " d where d.user_id = " + strconv.FormatUint(diamondAccount.UserId, 10) + " and d.operate_type = " + strconv.FormatUint(uint64(operateType), 10) + " and d.created_time >= from_unixtime(" + strconv.FormatInt(utils.GetZeroTime(time.Now()).Unix(), 10) + ")) t where t.n < " + strconv.Itoa(diamondOperateSet.FrequencyNum) + " )")
	}

	//-1,代表值无效,由参数给与
	var upateDiamondNum mysql.Num
	if diamondOperateSet.DiamondNum == -1 {
		upateDiamondNum = diamondNum
	} else {
		upateDiamondNum = mysql.Num(diamondOperateSet.DiamondNum)
	}

	var afterNum mysql.Num
	if diamondOperateSet.AddReduce == mysql.ADD {
		afterNum = diamondAccount.DiamondNum + upateDiamondNum
	} else if diamondOperateSet.AddReduce == mysql.REDUCE {
		if diamondAccount.DiamondNum < upateDiamondNum {
			return nil, bizerr.DiamondNoEnough
		}
		afterNum = diamondAccount.DiamondNum - upateDiamondNum
	} else {
		return nil, myerr.NewSysError("AddReduce 值错误:" + mysql.TypeToString(mysql.Type(diamondOperateSet.AddReduce)))
	}

	diamondAccountDetail := &DiamondAccountDetail{
		Model:            diamondAccount.Model,
		UserId:           diamondAccount.UserId,
		DiamondAccountId: diamondAccount.ID,
		OperateId:        diamondOperateSet.ID,
		OperateType:      diamondOperateSet.Type,
		OriginId:         originId,
		AddReduce:        diamondOperateSet.AddReduce,
		Num:              upateDiamondNum,
		Remark:           diamondOperateSet.Name,
		BefNum:           diamondAccount.DiamondNum,
		AftNum:           afterNum,
		diamondAccount:   diamondAccount,
	}
	return diamondAccountDetail, err
}

func (diamondAccountDetail *DiamondAccountDetail) PersistentNoInTransactional() error {
	//fixme: 这里有点奇怪, diamondAccount持久化动作在diamondAccountDetail持久化之后,RowsAffected 就一定是0
	txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount)
	if diamondAccountDetail.diamondAccount.CheckUpdateCondition() {
		txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition())
	}
	if diamondAccountDetail.AddReduce == mysql.ADD {
		//增加
		txDiamondAccount.UpdateColumn("diamond_num", gorm.Expr("diamond_num + ?", diamondAccountDetail.Num))
	} else if diamondAccountDetail.AddReduce == mysql.REDUCE {
		//减少,保证不能扣成负数
		txDiamondAccount.Where("diamond_num >= ?", diamondAccountDetail.Num).UpdateColumn("diamond_num", gorm.Expr("diamond_num - ?", diamondAccountDetail.Num))
	} else {
		myerr.NewSysError("addReduce 枚举错误 value:" + mysql.TypeToString(mysql.Type(diamondAccountDetail.AddReduce)))
	}
	if err := txDiamondAccount.Error; err != nil {
		return myerr.WrapErr(err)
	}
	if txDiamondAccount.RowsAffected == 0 {
		diamondAccountDetail.Log.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce)
		return myerr.NewWaring("gorm condition update.RowsAffected = 0")
	}

	//持久化diamondAccountDetail
	//if err := model.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil {
	//	return myerr.WrapErr(err)
	//}
	if err := diamondAccountDetail.DB().Table(diamondAccountDetail.TableName()).Save(diamondAccountDetail).Error; err != nil {
		return myerr.WrapErr(err)
	}
	//改变diamondAccount值
	if diamondAccountDetail.diamondAccount == nil {
		return myerr.NewSysError("持久化错误, 模型:DiamondAccountDetail 中没有diamondAccount, DiamondAccountDetail.Id =" + strconv.Itoa(int(diamondAccountDetail.ID)))
	}

	var newDiamondAccount DiamondAccount
	if err := diamondAccountDetail.Db.First(&newDiamondAccount, diamondAccountDetail.diamondAccount.ID).Error; err != nil {
		return myerr.WrapErr(err)
	}

	if newDiamondAccount.DiamondNum < 0 {
		return myerr.NewSysError("diamond_account表中,diamond_num 不能小于0, diamondAccount.id = " + strconv.Itoa(int(newDiamondAccount.ID)))
	}
	return nil
}

//群组支持
func (diamondAccount *DiamondAccount) GroupSupportAdmin(groupSupportAwardId mysql.ID, diamondNum uint32) (*DiamondAccountDetail, error) {
	return diamondAccount.addDiamondAccountDetail(diamond_e.GroupSupportAdmin, groupSupportAwardId, diamondNum)
}

func (diamondAccountDetail *DiamondAccountDetail) Persistent() error {
	//fixme: 这里有点奇怪, diamondAccount持久化动作在diamondAccountDetail持久化之后,RowsAffected 就一定是0
	txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount)
	if diamondAccountDetail.diamondAccount.CheckUpdateCondition() {
		txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition())
	}
	if diamondAccountDetail.AddReduce == mysql.ADD {
		//增加
		txDiamondAccount.UpdateColumn("diamond_num", gorm.Expr("diamond_num + ?", diamondAccountDetail.Num))
	} else if diamondAccountDetail.AddReduce == mysql.REDUCE {
		//减少,保证不能扣成负数
		txDiamondAccount.Where("diamond_num >= ?", diamondAccountDetail.Num).UpdateColumn("diamond_num", gorm.Expr("diamond_num - ?", diamondAccountDetail.Num))
	} else {
		myerr.NewSysError("addReduce 枚举错误 value:" + mysql.TypeToString(mysql.Type(diamondAccountDetail.AddReduce)))
	}
	if err := txDiamondAccount.Error; err != nil {
		return myerr.WrapErr(err)
	}
	if txDiamondAccount.RowsAffected == 0 {
		mylogrus.MyLog.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce)
		return myerr.NewWaring("gorm condition update.RowsAffected = 0")
	}

	//持久化diamondAccountDetail
	//if err := model.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil {
	//	return myerr.WrapErr(err)
	//}
	if err := diamondAccountDetail.DB().Table(diamondAccountDetail.TableName()).Save(diamondAccountDetail).Error; err != nil {
		return myerr.WrapErr(err)
	}
	//改变diamondAccount值
	if diamondAccountDetail.diamondAccount == nil {
		return myerr.NewSysError("持久化错误, 模型:DiamondAccountDetail 中没有diamondAccount, DiamondAccountDetail.Id =" + strconv.Itoa(int(diamondAccountDetail.ID)))
	}

	var newDiamondAccount DiamondAccount
	if err := diamondAccountDetail.Db.First(&newDiamondAccount, diamondAccountDetail.diamondAccount.ID).Error; err != nil {
		return myerr.WrapErr(err)
	}

	if newDiamondAccount.DiamondNum < 0 {
		return myerr.NewSysError("diamond_account表中,diamond_num 不能小于0, diamondAccount.id = " + strconv.Itoa(int(newDiamondAccount.ID)))
	}
	return nil
}

//群组支持
func (diamondAccount *DiamondAccount) GroupSupportMgr(groupSupportAwardId mysql.ID, diamondNum uint32) (*DiamondAccountDetail, error) {
	return diamondAccount.addDiamondAccountDetail(diamond_e.GroupSupportMgr, groupSupportAwardId, diamondNum)
}

//群组IM群发
func (diamondAccount *DiamondAccount) GroupImMass() (*DiamondAccountDetail, error) {
	return diamondAccount.addDiamondAccountDetail(diamond_e.GroupIMMass, 0, 0)
}

//购买自定义群组主题
func (diamondAccount *DiamondAccount) BuyGroupCustomTheme(diamondAccountDetailId mysql.ID) (*DiamondAccountDetail, error) {
	return diamondAccount.addDiamondAccountDetail(diamond_e.GroupCustomTheme, diamondAccountDetailId, 0)
}