package rule

import (
	"code.fnuoos.com/EggPlanet/egg_models.git/src/implement"
	"code.fnuoos.com/EggPlanet/egg_models.git/src/model"
	zhios_order_relate_utils "code.fnuoos.com/EggPlanet/egg_models.git/utils"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git/md"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git/svc"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git/utils/cache"
	"errors"
	"fmt"
	"github.com/shopspring/decimal"
	"time"
	"xorm.io/xorm"
)

// DealUserWallet 处理给用户金额
func DealUserWallet(session *xorm.Session, req md.DealUserWalletReq) (err error) {
	if req.Amount < 0 {
		req.Amount = 0
	}
	//1、分布式锁阻拦
	requestIdPrefix := fmt.Sprintf(md.UserWalletRedisKey, req.Uid)
	cb, err := svc.HandleDistributedLockForUserWallet(zhios_order_relate_utils.Int64ToStr(req.Uid), requestIdPrefix)
	if err != nil {
		return err
	}
	if cb != nil {
		defer cb() // 释放锁
	}

	//2、计算&&组装数据
	now := time.Now()
	userAmount, err := GetUserWalletAmount(session, req.Uid)
	if err != nil {
		return err
	}
	amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(4)

	var userWalletFlow model.UserWalletFlow
	userWalletFlow.Uid = req.Uid
	userWalletFlow.Title = req.Title
	userWalletFlow.Kind = req.Kind
	userWalletFlow.BeforeAmount = userAmount
	userWalletFlow.Amount = amountValue.String()
	userWalletFlow.CreateAt = now.Format("2006-01-02 15:04:05")

	if req.Direction == "add" {
		userWalletFlow.Direction = 1
		userWalletFlow.AfterAmount = amountValue.Add(amountValue).RoundFloor(8).String()
	} else if req.Direction == "sub" {
		userWalletFlow.Direction = 2
		userWalletFlow.AfterAmount = amountValue.Sub(amountValue).RoundFloor(8).String()
		if zhios_order_relate_utils.StrToFloat64(userWalletFlow.AfterAmount) < 0 {
			return errors.New("用户钱包余额不足")
		}
	} else {
		err = errors.New("错误的Direction类型")
		return err
	}

	//3、插入 `user_wallet_flow` 记录
	userWalletFlowDb := implement.NewUserWalletFlowDb(session.Engine())
	_, err = userWalletFlowDb.UserWalletFlowInsertBySession(session, &userWalletFlow)
	if err != nil {
		return err
	}

	//4、修改 `user_wallet`的amount值 && 及缓存
	err = SetUserWalletAmount(session, userWalletFlow.AfterAmount, req.Uid, true)
	if err != nil {
		return err
	}

	return nil
}

// GetUserWalletAmount 获取用户钱包余额
func GetUserWalletAmount(session *xorm.Session, uid int64) (amount string, err error) {
	redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
	amount, err = cache.GetString(redisKey)
	if err != nil {
		if err.Error() == "redigo: nil returned" {
			userWalletDb := implement.NewUserWalletDb(session.Engine())
			userVirtualAmount, err := userWalletDb.GetUserVirtualWallet(uid)
			if err != nil {
				return amount, err
			}
			if userVirtualAmount == nil {
				amount = "0"
			} else {
				amount = userVirtualAmount.Amount
			}
			//将获取到的余额值缓存至redis
			_ = SetUserWalletAmount(session, amount, uid, false)
			return amount, nil
		}
		return amount, err
	}
	return amount, nil
}

// SetUserWalletAmount 设置缓存的用户虚拟币积分余额
func SetUserWalletAmount(session *xorm.Session, amount string, uid int64, isUpdateDb bool) error {
	redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
	if isUpdateDb {
		_, err := session.Where("uid=?", uid).Update(model.UserWallet{
			Uid:    uid,
			Amount: amount,
		})
		if err != nil {
			return err
		}
	}
	//TODO::默认缓存1小时 (先调整为 20 min)
	_, err := cache.SetEx(redisKey, zhios_order_relate_utils.StrToFloat64(amount), 60*20)
	if err != nil {
		return err
	}
	return nil
}