package sys_user_payment

import (
	"context"

	"kami/internal/consts"
	"kami/internal/dao"
	"kami/internal/model"
	"kami/internal/model/do"
	"kami/internal/model/entity"
	"kami/internal/service"
	"kami/utility/config"
	"kami/utility/utils"

	"github.com/shopspring/decimal"

	"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/gtime"
)

func init() {
	service.RegisterSysUserPayment(New())
}

type sSysUserPayment struct{}

func New() *sSysUserPayment {
	return &sSysUserPayment{}
}

// Add 往钱包中添加当前用户数据
func (s *sSysUserPayment) Add(ctx context.Context, input model.SysUserPaymentInput, tx gdb.TX) (err error) {
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1SysUserPayment.Columns().UserId, input.UserId)
	if tx != nil {
		m = m.TX(tx)
	}
	_, err = m.Save(do.V1SysUserPayment{
		UserId:                input.UserId,
		Balance:               0,
		TotalDeposits:         0,
		TotalDepositCount:     0,
		TotalConsumption:      0,
		TotalConsumptionCount: 0,
		Status:                consts.UserPaymentStatusNormal,
	})
	return
}

// Recharge 往钱包内充值
func (s *sSysUserPayment) Recharge(ctx context.Context, input model.SysUserPaymentRechargeOrConsumeInput, tx gdb.TX) (recordId int64, err error) {
	recordId = 0
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1SysUserPayment.Columns().UserId, input.UserId)
	if tx != nil {
		m = m.TX(tx)
	}
	err = m.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		m = m.TX(tx)
		data := entity.V1SysUserPayment{}
		_ = m.Scan(&data)
		if data.Id == 0 {
			id, err2 := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1()).TX(tx).
				InsertAndGetId(do.V1SysUserPayment{
					UserId:            input.UserId,
					Balance:           input.Amount,
					TotalDeposits:     input.Amount,
					TotalDepositCount: 1,
					LastDepositTime:   gtime.Now(),
				})
			data.Id = uint(id)
			if err2 != nil {
				return err2
			}
		} else {
			_, err = m.Update(&g.Map{
				dao.V1SysUserPayment.Columns().Balance: gdb.Counter{
					Field: dao.V1SysUserPayment.Columns().Balance,
					Value: input.Amount.InexactFloat64(),
				},
				dao.V1SysUserPayment.Columns().TotalDeposits: gdb.Counter{
					Field: dao.V1SysUserPayment.Columns().TotalDeposits,
					Value: input.Amount.InexactFloat64(),
				},
				dao.V1SysUserPayment.Columns().TotalDepositCount: gdb.Counter{
					Field: dao.V1SysUserPayment.Columns().TotalDepositCount,
					Value: 1,
				},
				dao.V1SysUserPayment.Columns().LastDepositTime: gtime.Now(),
			})
		}
		recordId, err = s.AddRecord(ctx, model.SysUserPaymentRecordInput{
			UserId:          input.UserId,
			OrderNo:         input.OrderNo,
			PaymentId:       int(data.Id),
			Amount:          input.Amount,
			Notes:           input.Remark,
			TransactionType: input.TransactionType,
		}, tx)
		return err
	})
	return
}

// Consumption 消耗金额
func (s *sSysUserPayment) Consumption(ctx context.Context, input *model.SysUserPaymentRechargeOrConsumeInput, tx gdb.TX) (recordId int64, err error) {
	recordId = 0
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1SysUserPayment.Columns().UserId, input.UserId)
	if tx != nil {
		m = m.TX(tx)
	}
	err = m.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		m = m.TX(tx)
		data := entity.V1SysUserPayment{}
		_ = m.Scan(&data)
		if data.Id == 0 {
			id, err2 := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1()).TX(tx).
				InsertAndGetId(do.V1SysUserPayment{
					UserId:                input.UserId,
					Balance:               0 - input.Amount.InexactFloat64(),
					TotalConsumption:      input.Amount,
					TotalConsumptionCount: 1,
					LastConsumptionTime:   gtime.Now(),
				})
			data.Id = uint(id)
			if err2 != nil {
				return err2
			}
		} else {
			_, err = m.Update(&g.Map{
				dao.V1SysUserPayment.Columns().Balance: gdb.Counter{
					Field: dao.V1SysUserPayment.Columns().Balance,
					Value: 0 - input.Amount.InexactFloat64(),
				},
				dao.V1SysUserPayment.Columns().TotalConsumption: gdb.Counter{
					Field: dao.V1SysUserPayment.Columns().TotalConsumption,
					Value: input.Amount.InexactFloat64(),
				},
				dao.V1SysUserPayment.Columns().TotalConsumptionCount: gdb.Counter{
					Field: dao.V1SysUserPayment.Columns().TotalConsumptionCount,
					Value: 1,
				},
				dao.V1SysUserPayment.Columns().LastConsumptionTime: gtime.Now(),
			})
		}
		recordId, err = s.AddRecord(ctx, model.SysUserPaymentRecordInput{
			UserId:          input.UserId,
			OrderNo:         input.OrderNo,
			PaymentId:       int(data.Id),
			Amount:          input.Amount,
			Notes:           input.Remark,
			Category:        input.Category,
			TransactionType: input.TransactionType,
		}, tx)
		return err
	})
	return
}

// CheckBalanceEnough 查询钱包内钱是不是够充值
func (s *sSysUserPayment) CheckBalanceEnough(ctx context.Context, input *model.SysUserPaymentCheckBalanceInput) (isEnough bool, err error) {
	isEnough = false
	data, err := s.GetDetailById(ctx, &model.SysUserPaymentGetOneInput{
		UserId:    input.UserId,
		PaymentId: input.PaymentId,
	})
	if err != nil || data == nil || data.Id == 0 {
		return
	}
	if data.Balance.GreaterThanOrEqual(decimal.NewFromFloat(consts.AppleCardUserAccountMinBalance)) {
		isEnough = true
	}
	return
}

// CheckAmountEnough 查询钱包内钱是不是够充值
func (s *sSysUserPayment) CheckAmountEnough(ctx context.Context, input *model.SysUserPaymentCheckBalanceInput) (isEnough bool, err error) {
	isEnough = false
	data, err := s.GetDetailById(ctx, &model.SysUserPaymentGetOneInput{
		UserId:    input.UserId,
		PaymentId: input.PaymentId,
	})
	if err != nil || data == nil || data.Id == 0 {
		return
	}
	if data.Balance.GreaterThanOrEqual(input.Amount) {
		isEnough = true
	}
	return
}

// Edit 修改数据
func (s *sSysUserPayment) Edit(ctx context.Context, input model.SysUserPaymentInput, tx gdb.TX) (err error) {
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1SysUserPayment.Columns().UserId, input.UserId)
	if tx != nil {
		m = m.TX(tx)
	}
	_, _ = m.Update(do.V1SysUserPayment{})
	return
}

// List 查询钱包列表
func (s *sSysUserPayment) List(ctx context.Context, input model.SysUserPaymentListInput) (total int, list []*entity.V1SysUserPayment, err error) {
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1())
	//if input. != "" {
	//	m = m.Where(dao.V1SysUserPayment.Columns().UserId, input.UserId)
	//}
	err = m.Page(input.Current, input.PageSize).ScanAndCount(&list, &total, true)
	err = utils.HandleNoRowsError(err)
	return
}

// GetDetailById 查询单个用户的钱包信息
func (s *sSysUserPayment) GetDetailById(ctx context.Context, input *model.SysUserPaymentGetOneInput) (res *entity.V1SysUserPayment, err error) {
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1())
	if input == nil || (input.PaymentId == 0 && input.UserId == "") {
		return nil, gerror.New("参数错误")
	}
	if input.PaymentId != 0 {
		m = m.Where(dao.V1SysUserPayment.Columns().Id, input.PaymentId)
	}
	if input.UserId != "" {
		m = m.Where(dao.V1SysUserPayment.Columns().UserId, input.UserId)
	}
	err = m.Scan(&res)
	err = utils.HandleNoRowsError(err)
	return
}

// Delete 删除钱包信息
func (s *sSysUserPayment) Delete(ctx context.Context, input model.SysUserPaymentDeleteInput, tx gdb.TX) (err error) {
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1()).
		Where(dao.V1SysUserPayment.Columns().UserId, input.UserId)
	if tx != nil {
		m = m.TX(tx)
	}
	_, err = m.Delete()
	return
}

// GetAllByMinAmount 获取所有金额在minAmount以上的钱包
func (s *sSysUserPayment) GetAllByMinAmount(ctx context.Context, minAmount float64, tx gdb.TX) (list []*entity.V1SysUserPayment, err error) {
	list = make([]*entity.V1SysUserPayment, 0)
	m := dao.V1SysUserPayment.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	err = m.WhereGTE(dao.V1SysUserPayment.Columns().Balance, minAmount).Scan(&list)
	return
}
