package credit_balance

import (
	"context"
	"github.com/suyuan32/simple-admin-common/msg/errormsg"
	"github.com/suyuan32/simple-admin-core/rpc/types/core"
	"github.com/zeromicro/go-zero/core/errorx"
	"math"
	"wechat-api/ent"
	"wechat-api/ent/creditbalance"

	"wechat-api/internal/svc"
	"wechat-api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type OperateCreditBalanceLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewOperateCreditBalanceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OperateCreditBalanceLogic {
	return &OperateCreditBalanceLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx}
}

func (l *OperateCreditBalanceLogic) OperateCreditBalance(req *types.CreditBalanceOperateReq) (*types.BaseMsgResp, error) {
	isAdmin := l.ctx.Value("isAdmin").(bool)

	if !isAdmin {
		return nil, errorx.NewInvalidArgumentError("权限不足")
	}

	if req.Number == nil || *req.Number == 0 {
		return nil, errorx.NewInvalidArgumentError("Number参数非法")
	}

	_, err := l.svcCtx.CoreRpc.GetDepartmentById(l.ctx, &core.IDReq{Id: *req.OrganizationId})
	if err != nil {
		return nil, errorx.NewAlreadyExistsError("租户不存在")
	}

	creditBalance, err := l.svcCtx.DB.CreditBalance.Query().Where(creditbalance.OrganizationID(*req.OrganizationId)).Only(l.ctx)
	if err != nil && ent.IsNotFound(err) {
		creditBalance, err = l.svcCtx.DB.CreditBalance.Create().
			SetOrganizationID(*req.OrganizationId).
			SetBalance(0).
			Save(l.ctx)
	}

	var ntype int
	if *req.Number > 0 {
		ntype = 2
	} else {
		ntype = 1
	}

	userId := l.ctx.Value("userId").(string)
	tx, err := l.svcCtx.DB.Tx(context.Background())

	var beforeNumber, afterNumber float64
	if creditBalance == nil {
		beforeNumber = 0
		afterNumber = roundTo(*req.Number, 6)
	} else {
		beforeNumber = roundTo(creditBalance.Balance, 6)
		afterNumber = roundTo(beforeNumber, 6) + roundTo(*req.Number, 6)
	}

	l.Logger.Infof("number=%v beforeNumber=%v afterNumber=%v payNumber=%v\n",
		roundTo(*req.Number, 6),
		roundTo(beforeNumber, 6),
		roundTo(afterNumber, 6),
		roundTo(*req.PayNumber, 2),
	)

	_, err = tx.CreditUsage.Create().
		SetNumber(roundTo(*req.Number, 6)).
		SetNotNilPayMethod(req.PayMethod).        //支付方式
		SetPayNumber(roundTo(*req.PayNumber, 2)). //支付金额
		SetNtype(ntype).
		SetNid(0).
		SetTable("").
		SetNotNilReason(req.Reason).
		SetNotNilOrganizationID(req.OrganizationId).
		SetOperator(userId).
		SetBeforeNumber(beforeNumber).
		SetAfterNumber(afterNumber).
		Save(l.ctx)
	if err != nil {
		l.Logger.Errorf("create credit_usage error:%v\n", err)
		_ = tx.Rollback()
		return nil, errorx.NewInvalidArgumentError("创建租户积分明细失败，请重试")
	}

	if *req.Number > 0 {
		if creditBalance == nil {
			_, err = l.svcCtx.DB.CreditBalance.Create().
				SetOrganizationID(*req.OrganizationId).
				SetBalance(roundTo(*req.Number, 6)).
				Save(l.ctx)
			if err != nil {
				l.Logger.Errorf("create credit_balance error:%v\n", err)
				_ = tx.Rollback()
				return nil, errorx.NewInvalidArgumentError("创建租户积分余额失败，请重试")
			}
		} else {
			_, err = l.svcCtx.DB.CreditBalance.Update().Where(creditbalance.OrganizationID(*req.OrganizationId)).SetBalance(creditBalance.Balance + roundTo(*req.Number, 6)).Save(l.ctx)
			if err != nil {
				l.Logger.Errorf("update credit_balance error:%v\n", err)
				_ = tx.Rollback()
				return nil, errorx.NewInvalidArgumentError("修改租户积分余额失败，请重试.")
			}
		}
	} else {
		_, err := l.svcCtx.DB.CreditBalance.Update().Where(creditbalance.OrganizationID(*req.OrganizationId)).SetBalance(creditBalance.Balance + *req.Number).Save(l.ctx)
		if err != nil {
			l.Logger.Errorf("update credit_balance error:%v\n", err)
			_ = tx.Rollback()
			return nil, errorx.NewInvalidArgumentError("修改租户积分余额失败，请重试...")
		}
	}
	_ = tx.Commit()

	return &types.BaseMsgResp{
		Code: 0,
		Msg:  errormsg.Success,
	}, nil
}

func roundTo(num float64, precision int) float64 {
	scale := math.Pow(10, float64(precision))
	result := math.Round(num*scale) / scale

	return result
}
