package payments import ( "context" "fmt" "time" "github.com/gofrs/uuid/v5" "github.com/saveinmed/backend-go/internal/domain" ) // MockGateway provides a fictional payment gateway for testing and development. // All payments are automatically approved after a short delay. type MockGateway struct { MarketplaceCommission float64 AutoApprove bool // If true, payments are auto-approved } func NewMockGateway(commission float64, autoApprove bool) *MockGateway { return &MockGateway{ MarketplaceCommission: commission, AutoApprove: autoApprove, } } func (g *MockGateway) CreatePreference(ctx context.Context, order *domain.Order, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentPreference, error) { select { case <-ctx.Done(): return nil, ctx.Err() default: } fee := int64(float64(order.TotalCents) * (g.MarketplaceCommission / 100)) // Generate a mock payment ID mockPaymentID := uuid.Must(uuid.NewV7()) status := "pending" if g.AutoApprove { status = "approved" } pref := &domain.PaymentPreference{ OrderID: order.ID, Gateway: "mock", CommissionPct: g.MarketplaceCommission, MarketplaceFee: fee, SellerReceivable: order.TotalCents - fee, PaymentURL: fmt.Sprintf("/mock-payment/%s?status=%s", mockPaymentID.String(), status), } // Simulate minimal latency time.Sleep(5 * time.Millisecond) return pref, nil } // CreatePayment simulates a direct payment. func (g *MockGateway) CreatePayment(ctx context.Context, order *domain.Order, token, issuerID, paymentMethodID string, installments int, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentResult, error) { return &domain.PaymentResult{ PaymentID: uuid.Must(uuid.NewV7()).String(), Status: "approved", Gateway: "mock", Message: "Mock direct payment approved", }, nil } // CreatePixPayment simulates a Pix payment generation. func (g *MockGateway) CreatePixPayment(ctx context.Context, order *domain.Order) (*domain.PixPaymentResult, error) { return &domain.PixPaymentResult{ PaymentID: uuid.Must(uuid.NewV7()).String(), OrderID: order.ID, Gateway: "mock", PixKey: "mock@saveinmed.com", QRCode: "mock_qr_code", QRCodeBase64: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...", CopyPasta: "mock_copy_pasta_code", AmountCents: order.TotalCents + order.ShippingFeeCents, Status: "pending", ExpiresAt: time.Now().Add(30 * time.Minute), }, nil } // CreateBoletoPayment simulates a Boleto generation. func (g *MockGateway) CreateBoletoPayment(ctx context.Context, order *domain.Order, payer *domain.User) (*domain.BoletoPaymentResult, error) { return &domain.BoletoPaymentResult{ PaymentID: uuid.Must(uuid.NewV7()).String(), OrderID: order.ID, Gateway: "mock", BoletoURL: "https://example.com/mock-boleto.pdf", BarCode: "00000000000000000000000000000000000000000000", DigitableLine: "00000.00000 00000.000000 00000.000000 0 00000000000000", AmountCents: order.TotalCents + order.ShippingFeeCents, DueDate: time.Now().AddDate(0, 0, 3), Status: "pending", }, nil } // GetPaymentStatus returns a simulated payment status. func (g *MockGateway) GetPaymentStatus(ctx context.Context, paymentID string) (*domain.PaymentWebhookEvent, error) { return &domain.PaymentWebhookEvent{ PaymentID: paymentID, Status: "approved", Gateway: "mock", }, nil } // ConfirmPayment simulates payment confirmation for the mock gateway. func (g *MockGateway) ConfirmPayment(ctx context.Context, paymentID string) (*domain.PaymentResult, error) { select { case <-ctx.Done(): return nil, ctx.Err() default: } // Always approve in mock mode return &domain.PaymentResult{ PaymentID: paymentID, Status: "approved", Gateway: "mock", Message: "Pagamento fictício aprovado automaticamente", ConfirmedAt: time.Now(), }, nil } // RefundPayment simulates a refund for the mock gateway. func (g *MockGateway) RefundPayment(ctx context.Context, paymentID string, amountCents int64) (*domain.RefundResult, error) { select { case <-ctx.Done(): return nil, ctx.Err() default: } return &domain.RefundResult{ RefundID: uuid.Must(uuid.NewV7()).String(), PaymentID: paymentID, AmountCents: amountCents, Status: "refunded", RefundedAt: time.Now(), }, nil }