325 lines
10 KiB
Go
325 lines
10 KiB
Go
package atlas
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
"strconv"
|
||
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/ports"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||
)
|
||
|
||
type Service struct {
|
||
virtualGameSvc virtualgameservice.VirtualGameService
|
||
repo repository.VirtualGameRepository
|
||
client *Client
|
||
walletSvc *wallet.Service
|
||
transfetStore ports.TransferStore
|
||
cfg *config.Config
|
||
}
|
||
|
||
func New(virtualGameSvc virtualgameservice.VirtualGameService, repo repository.VirtualGameRepository, client *Client, walletSvc *wallet.Service, transferStore ports.TransferStore, cfg *config.Config) *Service {
|
||
return &Service{
|
||
virtualGameSvc: virtualGameSvc,
|
||
repo: repo,
|
||
client: client,
|
||
walletSvc: walletSvc,
|
||
transfetStore: transferStore,
|
||
cfg: cfg,
|
||
}
|
||
}
|
||
|
||
func (s *Service) InitGame(ctx context.Context, req domain.AtlasGameInitRequest) (*domain.AtlasGameInitResponse, error) {
|
||
|
||
body := map[string]any{
|
||
"game": req.Game,
|
||
"partner_id": s.client.PartnerID,
|
||
"casino_id": s.client.CasinoID,
|
||
"language": req.Language,
|
||
"currency": req.Currency,
|
||
"player_id": req.PlayerID,
|
||
}
|
||
|
||
// 3. Call the Atlas client
|
||
var res domain.AtlasGameInitResponse
|
||
if err := s.client.post(ctx, "/init", body, &res); err != nil {
|
||
return nil, fmt.Errorf("failed to initialize game: %w", err)
|
||
}
|
||
|
||
return &res, nil
|
||
}
|
||
|
||
func (s *Service) GetUserData(ctx context.Context, req domain.AtlasGetUserDataRequest) (*domain.AtlasGetUserDataResponse, error) {
|
||
// 1. Validate casino_id and hash if needed
|
||
if req.CasinoID != s.client.CasinoID {
|
||
return nil, fmt.Errorf("invalid casino_id")
|
||
}
|
||
// 2. Fetch player from DB
|
||
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||
}
|
||
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||
}
|
||
|
||
// 4. Build response
|
||
res := &domain.AtlasGetUserDataResponse{
|
||
PlayerID: req.PlayerID,
|
||
Balance: float64(wallet.RegularBalance),
|
||
}
|
||
|
||
return res, nil
|
||
}
|
||
|
||
func (s *Service) ProcessBet(ctx context.Context, req domain.AtlasBetRequest) (*domain.AtlasBetResponse, error) {
|
||
if req.CasinoID != s.client.CasinoID {
|
||
return nil, fmt.Errorf("invalid casino_id")
|
||
}
|
||
|
||
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||
}
|
||
|
||
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||
}
|
||
// if player == nil {
|
||
// return nil, ErrPlayerNotFound
|
||
// }
|
||
|
||
// 3. Check for duplicate transaction
|
||
// exists, err := s.repo.TransactionExists(ctx, req.TransactionID)
|
||
// if err != nil {
|
||
// return nil, fmt.Errorf("failed to check transaction: %w", err)
|
||
// }
|
||
// if exists {
|
||
// return nil, ErrDuplicateTransaction
|
||
// }
|
||
|
||
// // 4. Get current balance
|
||
// balance, err := s.walletSvc.GetBalance(ctx, req.PlayerID)
|
||
// if err != nil {
|
||
// return nil, fmt.Errorf("failed to fetch wallet balance: %w", err)
|
||
// }
|
||
|
||
// 5. Ensure sufficient balance
|
||
if float64(wallet.RegularBalance) < req.Amount {
|
||
return nil, domain.ErrInsufficientBalance
|
||
}
|
||
|
||
// 6. Deduct amount from wallet (record transaction)
|
||
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)-req.Amount))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to debit wallet: %w", err)
|
||
}
|
||
|
||
// 7. Save transaction record to DB (optional but recommended)
|
||
// if err := s.repo.SaveBetTransaction(ctx, req); err != nil {
|
||
// // log warning but don’t fail response to Atlas
|
||
// fmt.Printf("warning: failed to save bet transaction: %v\n", err)
|
||
// }
|
||
|
||
// 8. Build response
|
||
res := &domain.AtlasBetResponse{
|
||
PlayerID: req.PlayerID,
|
||
Balance: float64(wallet.RegularBalance) - req.Amount,
|
||
}
|
||
|
||
return res, nil
|
||
}
|
||
|
||
func (s *Service) ProcessBetWin(ctx context.Context, req domain.AtlasBetWinRequest) (*domain.AtlasBetWinResponse, error) {
|
||
if req.CasinoID != s.client.CasinoID {
|
||
return nil, fmt.Errorf("invalid casino_id")
|
||
}
|
||
|
||
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||
}
|
||
|
||
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||
}
|
||
|
||
// 5. Ensure sufficient balance
|
||
if float64(wallet.RegularBalance) < req.BetAmount {
|
||
return nil, domain.ErrInsufficientBalance
|
||
}
|
||
|
||
// 6. Deduct amount from wallet (record transaction)
|
||
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)-req.BetAmount))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to debit wallet: %w", err)
|
||
}
|
||
|
||
if req.WinAmount > 0 {
|
||
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+req.WinAmount))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||
}
|
||
}
|
||
|
||
// 8. Build response
|
||
res := &domain.AtlasBetWinResponse{
|
||
PlayerID: req.PlayerID,
|
||
Balance: float64(wallet.RegularBalance),
|
||
}
|
||
|
||
return res, nil
|
||
}
|
||
|
||
func (s *Service) ProcessRoundResult(ctx context.Context, req domain.RoundResultRequest) (*domain.RoundResultResponse, error) {
|
||
if req.PlayerID == "" || req.TransactionID == "" {
|
||
return nil, errors.New("missing player_id or transaction_id")
|
||
}
|
||
|
||
// Credit player with win amount if > 0
|
||
if req.Amount > 0 {
|
||
// This will credit player's balance
|
||
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||
}
|
||
|
||
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||
}
|
||
|
||
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+req.Amount))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||
}
|
||
|
||
}
|
||
|
||
return &domain.RoundResultResponse{Success: true}, nil
|
||
}
|
||
|
||
func (s *Service) ProcessRollBack(ctx context.Context, req domain.RollbackRequest) (*domain.RollbackResponse, error) {
|
||
if req.PlayerID == "" || req.BetTransactionID == "" {
|
||
return nil, errors.New("missing player_id or transaction_id")
|
||
}
|
||
|
||
// Credit player with win amount if > 0
|
||
// This will credit player's balance
|
||
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||
}
|
||
|
||
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||
}
|
||
|
||
transfer, err := s.transfetStore.GetTransferByReference(ctx, req.BetTransactionID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch transfer for reference %s: %w", req.BetTransactionID, err)
|
||
}
|
||
|
||
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+float64(transfer.Amount)))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||
}
|
||
|
||
err = s.transfetStore.UpdateTransferStatus(ctx, transfer.ID, string(domain.STATUS_CANCELLED))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to update transfer status: %w", err)
|
||
}
|
||
|
||
err = s.transfetStore.UpdateTransferVerification(ctx, transfer.ID, true)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to update transfer verification: %w", err)
|
||
}
|
||
|
||
return &domain.RollbackResponse{Success: true}, nil
|
||
}
|
||
|
||
func (s *Service) CreateFreeSpin(ctx context.Context, req domain.FreeSpinRequest) (*domain.FreeSpinResponse, error) {
|
||
|
||
body := map[string]any{
|
||
"casino_id": s.client.CasinoID,
|
||
"freespins_count": req.FreeSpinsCount,
|
||
"end_date": req.EndDate,
|
||
"player_id": req.PlayerID,
|
||
}
|
||
|
||
// 3. Call the Atlas client
|
||
var res domain.FreeSpinResponse
|
||
if err := s.client.post(ctx, "/freespin", body, &res); err != nil {
|
||
return nil, fmt.Errorf("failed to create free spin: %w", err)
|
||
}
|
||
|
||
return &res, nil
|
||
}
|
||
|
||
func (s *Service) ProcessFreeSpinResult(ctx context.Context, req domain.FreeSpinResultRequest) (*domain.FreeSpinResultResponse, error) {
|
||
|
||
if req.PlayerID == "" || req.TransactionID == "" {
|
||
return nil, errors.New("missing player_id or transaction_id")
|
||
}
|
||
|
||
// Credit player with win amount if > 0
|
||
if req.Amount > 0 {
|
||
// This will credit player's balance
|
||
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||
}
|
||
|
||
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||
}
|
||
|
||
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+req.Amount))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||
}
|
||
|
||
}
|
||
|
||
return &domain.FreeSpinResultResponse{Success: true}, nil
|
||
}
|
||
|
||
func (s *Service) ProcessJackPot(ctx context.Context, req domain.JackpotRequest) (*domain.JackpotResponse, error) {
|
||
|
||
if req.PlayerID == "" || req.TransactionID == "" {
|
||
return nil, errors.New("missing player_id or transaction_id")
|
||
}
|
||
|
||
// Credit player with win amount if > 0
|
||
if req.Amount > 0 {
|
||
// This will credit player's balance
|
||
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||
}
|
||
|
||
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||
}
|
||
|
||
_, err = s.walletSvc.AddToWallet(ctx, wallet.RegularID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||
}
|
||
|
||
}
|
||
|
||
return &domain.JackpotResponse{Success: true}, nil
|
||
}
|