package card_redeem_account

import (
	"context"
	"fmt"
	"kami/internal/consts"
	"kami/internal/dao"
	"kami/internal/model"
	"kami/internal/model/do"
	"kami/internal/model/entity"
	"kami/internal/service"
	"kami/utility/config"

	"github.com/duke-git/lancet/v2/pointer"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/shopspring/decimal"
)

// ReduceAmount 扣钱后并添加银行流水
func (a *sCardRedeemAccount) ReduceAmount(ctx context.Context, input *model.RedeemAccountAddHistory, tx gdb.TX) (err error) {
	m := dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1())

	if tx != nil {
		m = m.TX(tx)
	}

	err = m.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {

		_ = a.IncrementAmountCurrentCount(ctx, input.AccountId, input.Amount, tx)

		//判断当前金额是否超过账号允许充值上限
		accountInfo, err2 := a.GetOneById(ctx, input.AccountId, tx)
		if !pointer.IsNil(err2) || accountInfo.Id == "" {
			return gerror.New("当前账户不存在")
		}

		if err3 := a.AddHistory(ctx, &model.RedeemAccountAddHistory{
			AccountId:        input.AccountId,
			Amount:           input.Amount,
			OrderNo:          input.OrderNo,
			Remark:           "",
			Balance:          accountInfo.Balance,
			EffectiveBalance: accountInfo.Balance,
			OperationStatus:  input.OperationStatus,
			Cookie:           input.Cookie,
		}, tx); err3 != nil {
			glog.Error(ctx, err2)
		}

		if _, err3 := service.SysUserPayment().Consumption(ctx, &model.SysUserPaymentRechargeOrConsumeInput{
			UserId:          accountInfo.CreateUserId,
			OrderNo:         input.OrderNo,
			Amount:          decimal.NewFromFloat(input.Amount),
			Remark:          input.Remark,
			TransactionType: consts.UserPaymentRecordStatusConsume,
			Category:        consts.CardRedeemAccountCategory(accountInfo.Category),
		}, tx); err3 != nil {
			glog.Error(ctx, err2)
			return err2
		}
		return nil
	})
	return
}

// ReduceAmountWithReduction 预扣款后并添加银行流水
func (a *sCardRedeemAccount) ReduceAmountWithReduction(ctx context.Context, input *model.RedeemAccountAddHistory, tx gdb.TX) (err error) {
	m := dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	glog.Info(ctx, "开始预扣款")
	err = m.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {
		if err2 := a.ReduceAmount(ctx, input, tx2); err2 != nil {
			return err2
		}
		//账户添加扣款记录
		if err2 := a.AddDeductionRecord(ctx, &model.RedeemOrderAddDeductionRecordInput{
			OrderNo:   input.OrderNo,
			Balance:   input.Amount,
			AccountId: input.AccountId,
			Status:    consts.DeductionStatusStart,
		}, tx2); err2 != nil {
			return err2
		}
		//用户钱包添加扣款记录
		if err2 := service.SysUserPayment().Deduction(ctx, &model.DeductionInput{
			UserId:          input.AccountId,
			OrderNo:         input.OrderNo,
			Balance:         input.Amount,
			OrderCategory:   input.Category,
			OperationStatus: input.OperationStatus,
		}, tx2); err2 != nil {
			return err2
		}
		return err
	})
	return
}

// ReduceAmountWithReductionSucceed 添加预扣款成功记录
func (a *sCardRedeemAccount) ReduceAmountWithReductionSucceed(ctx context.Context, input *model.RedeemAccountReductionSucceed, tx gdb.TX) (err error) {
	//账户添加扣款记录
	if err2 := a.AddDeductionRecord(ctx, &model.RedeemOrderAddDeductionRecordInput{
		OrderNo:   input.OrderNo,
		Balance:   input.Amount,
		AccountId: input.AccountId,
		Status:    consts.DeductionStatusSuccess,
	}, tx); err2 != nil {
		return err2
	}

	accountInfo, _ := a.GetOneById(ctx, input.AccountId, tx)
	if (accountInfo.MaxAmountLimit > 0 && int(accountInfo.AmountTodaySum) >= accountInfo.MaxAmountLimit) ||
		(accountInfo.MaxCountLimit > 0 && accountInfo.AmountTodayCount >= accountInfo.MaxCountLimit) {
		_ = a.UpdateStatus(ctx, input.AccountId, consts.RedeemAccountForbiddenByMaxLimit, tx)
	}

	err = service.SysUserPayment().DeductionSuccess(ctx, &model.AddDeductionRecordInput{
		OrderNo:         input.OrderNo,
		OrderCategory:   input.Category,
		UserId:          accountInfo.CreateUserId,
		Balance:         input.Amount,
		OperationStatus: consts.DeductionStatusSuccess,
	}, tx)

	return
}

// ReduceAmountWithReductionFail 添加预扣款失败
func (a *sCardRedeemAccount) ReduceAmountWithReductionFail(ctx context.Context, input *model.RedeemAccountReductionSucceed, tx gdb.TX) (err error) {
	//账户添加扣款记录
	if err2 := a.AddDeductionRecord(ctx, &model.RedeemOrderAddDeductionRecordInput{
		OrderNo:   input.OrderNo,
		Balance:   input.Amount,
		AccountId: input.AccountId,
		Status:    consts.DeductionStatusReturn,
	}, tx); err2 != nil {
		return err2
	}

	if err2 := a.AddHistory(ctx, &model.RedeemAccountAddHistory{
		AccountId:       input.AccountId,
		Amount:          input.Amount,
		OrderNo:         input.OrderNo,
		Remark:          input.Remark,
		OperationStatus: consts.RedeemAccountOperationReturn,
	}, tx); err2 != nil {
		return
	}

	if err2 := a.DecrementAmountCurrentCount(ctx, input.AccountId, input.Amount, tx); err2 != nil {
		return err2
	}
	accountInfo, _ := a.GetOneById(ctx, input.AccountId, tx)

	err = service.SysUserPayment().DeductionReturn(ctx, &model.AddDeductionRecordInput{
		OrderNo:         input.OrderNo,
		OrderCategory:   input.Category,
		UserId:          accountInfo.CreateUserId,
		Balance:         input.Amount,
		Remark:          input.Remark,
		OperationStatus: consts.DeductionStatusReturn,
	}, tx)

	return
}

// ReducePartialAmountWithFail 部分退款
func (a *sCardRedeemAccount) ReducePartialAmountWithFail(ctx context.Context, input *model.RedeemAccountReductionSucceed, tx gdb.TX) (err error) {
	//账户添加扣款记录
	if err2 := a.AddDeductionRecord(ctx, &model.RedeemOrderAddDeductionRecordInput{
		OrderNo:   input.OrderNo,
		Balance:   input.Amount,
		AccountId: input.AccountId,
		Status:    consts.DeductionStatusReturn,
	}, tx); err2 != nil {
		return err2
	}

	if err2 := a.AddHistory(ctx, &model.RedeemAccountAddHistory{
		AccountId:       input.AccountId,
		Amount:          input.Amount,
		OrderNo:         input.OrderNo,
		Remark:          input.Remark,
		OperationStatus: consts.RedeemAccountOperationReturn,
	}, tx); err2 != nil {
		return
	}

	if err2 := a.DecrementAmount(ctx, input.AccountId, input.Amount, tx); err2 != nil {
		return err2
	}

	accountInfo, _ := a.GetOneById(ctx, input.AccountId, tx)

	if consts.RedeemAccountStatus(accountInfo.Status) == consts.RedeemAccountForbiddenByMaxLimit &&
		(accountInfo.MaxAmountLimit > 0 && int(accountInfo.AmountTodaySum) < accountInfo.MaxAmountLimit) &&
		(accountInfo.MaxCountLimit > 0 && accountInfo.AmountTodayCount < accountInfo.MaxCountLimit) {
		_ = a.UpdateStatus(ctx, input.AccountId, consts.RedeemAccountNormal, tx)
	}

	err = service.SysUserPayment().DeductionReturn(ctx, &model.AddDeductionRecordInput{
		OrderNo:         input.OrderNo,
		OrderCategory:   input.Category,
		UserId:          accountInfo.CreateUserId,
		Balance:         input.Amount,
		Remark:          input.Remark,
		OperationStatus: consts.DeductionStatusReturn,
	}, tx)
	return
}

// ResetTodayAmountTotal 遍历重置今天的充值记录
func (a *sCardRedeemAccount) ResetTodayAmountTotal(ctx context.Context) (err error) {
	_, _ = dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1()).Update(do.V1CardRedeemAccountInfo{
		AmountTodaySum:   0,
		AmountTodayCount: 0,
	})
	_, _ = dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1CardRedeemAccountInfo.Columns().Status, consts.RedeemAccountForbiddenByMaxLimit).
		WhereOr(dao.V1CardRedeemAccountInfo.Columns().Status, consts.RedeemAccountForbiddenDaily).Update(do.V1CardRedeemAccountInfo{
		Status: consts.RedeemAccountForbidden,
		Remark: "重置今日充值金额",
	})
	return
}

// IncrementAmountCurrentCount 金额计数+1
func (a *sCardRedeemAccount) IncrementAmountCurrentCount(ctx context.Context, accountId string, amount float64, tx gdb.TX) (err error) {
	m := dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	_, err = m.Where(dao.V1CardRedeemAccountInfo.Columns().Id, accountId).Update(&g.Map{
		dao.V1CardRedeemAccountInfo.Columns().Balance: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().Balance,
			Value: amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().EffectiveBalance: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().EffectiveBalance,
			Value: amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTotalSum: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTotalSum,
			Value: amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTotalCount: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTotalCount,
			Value: 1,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTodaySum: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTodaySum,
			Value: amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTodayCount: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTodayCount,
			Value: 1,
		},
	})
	return
}

// DecrementAmountCurrentCount 金额-1
func (a *sCardRedeemAccount) DecrementAmountCurrentCount(ctx context.Context, accountId string, amount float64, tx gdb.TX) (err error) {
	m := dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	_, err = m.Where(dao.V1CardRedeemAccountInfo.Columns().Id, accountId).Update(&g.Map{
		dao.V1CardRedeemAccountInfo.Columns().Balance: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().Balance,
			Value: -amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().EffectiveBalance: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().EffectiveBalance,
			Value: -amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTotalSum: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTotalSum,
			Value: -amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTotalCount: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTotalCount,
			Value: -1,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTodaySum: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTodaySum,
			Value: -amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTodayCount: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTodayCount,
			Value: -1,
		},
	})
	return
}

// DecrementAmount 退减金额
func (a *sCardRedeemAccount) DecrementAmount(ctx context.Context, accountId string, amount float64, tx gdb.TX) (err error) {
	m := dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	_, err = m.Where(dao.V1CardRedeemAccountInfo.Columns().Id, accountId).Update(&g.Map{
		dao.V1CardRedeemAccountInfo.Columns().Balance: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().Balance,
			Value: -amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().EffectiveBalance: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().EffectiveBalance,
			Value: -amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTotalSum: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTotalSum,
			Value: -amount,
		},
		dao.V1CardRedeemAccountInfo.Columns().AmountTodaySum: gdb.Counter{
			Field: dao.V1CardRedeemAccountInfo.Columns().AmountTodaySum,
			Value: -amount,
		},
	})
	return
}

// GetNormalOneByUserIdAndAmount 通过用户Id获取一个可用账户
func (a *sCardRedeemAccount) GetNormalOneByUserIdAndAmount(ctx context.Context, userId string, minAmount float64, tx gdb.TX) (data *entity.V1CardRedeemAccountInfo, err error) {
	m := dao.V1CardRedeemAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	err = m.Where(dao.V1CardRedeemAccountInfo.Columns().CreateUserId, userId).
		WhereGTE(fmt.Sprintf("`%s`-`%s`", dao.V1CardRedeemAccountInfo.Columns().MaxAmountLimit, dao.V1CardRedeemAccountInfo.Columns().MaxAmountLimit), minAmount).
		Where(dao.V1CardRedeemAccountInfo.Columns().Status, consts.RedeemAccountNormal).
		OrderRandom().Scan(&data)
	return
}
