351 lines
11 KiB
Go
351 lines
11 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.Float32()),
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *Service) ProcessBet(ctx context.Context, req domain.AtlasBetRequest) (*domain.AtlasBetResponse, error) {
|
|
// --- 1. Validate CasinoID ---
|
|
if req.CasinoID != s.client.CasinoID {
|
|
return nil, fmt.Errorf("BAD_REQUEST: invalid casino_id")
|
|
}
|
|
|
|
// --- 2. Validate PlayerID ---
|
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("BAD_REQUEST: invalid playerID %q", req.PlayerID)
|
|
}
|
|
|
|
// --- 3. Fetch player wallet ---
|
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch wallet for player %d: %w", playerIDInt, err)
|
|
}
|
|
|
|
// --- 4. Convert balance using Float32() ---
|
|
realBalance := float64(wallet.RegularBalance.Float32())
|
|
|
|
// --- 5. Ensure sufficient balance ---
|
|
if realBalance < req.Amount {
|
|
return nil, domain.ErrInsufficientBalance
|
|
}
|
|
|
|
// --- 6. Deduct amount from wallet ---
|
|
newBalance := realBalance - req.Amount
|
|
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.ToCurrency(float32(newBalance)))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to debit wallet: %w", err)
|
|
}
|
|
|
|
// --- 7. Build response ---
|
|
res := &domain.AtlasBetResponse{
|
|
PlayerID: req.PlayerID,
|
|
Balance: newBalance,
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *Service) ProcessBetWin(ctx context.Context, req domain.AtlasBetWinRequest) (*domain.AtlasBetWinResponse, error) {
|
|
// --- 1. Validate CasinoID ---
|
|
if req.CasinoID != s.client.CasinoID {
|
|
return nil, fmt.Errorf("BAD_REQUEST: invalid casino_id")
|
|
}
|
|
|
|
// --- 2. Validate PlayerID ---
|
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("BAD_REQUEST: invalid playerID %q", req.PlayerID)
|
|
}
|
|
|
|
// --- 3. Fetch player wallet ---
|
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch wallet for player %d: %w", playerIDInt, err)
|
|
}
|
|
|
|
// --- 4. Convert balance using Float32() ---
|
|
realBalance := float64(wallet.RegularBalance.Float32())
|
|
|
|
// --- 5. Ensure sufficient balance for bet ---
|
|
if realBalance < req.BetAmount {
|
|
return nil, domain.ErrInsufficientBalance
|
|
}
|
|
|
|
// --- 6. Deduct bet amount ---
|
|
debitedBalance := realBalance - req.BetAmount
|
|
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.ToCurrency(float32(debitedBalance)))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to debit wallet: %w", err)
|
|
}
|
|
|
|
// --- 7. Apply win amount (if any) ---
|
|
finalBalance := debitedBalance
|
|
if req.WinAmount > 0 {
|
|
finalBalance = debitedBalance + req.WinAmount
|
|
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.ToCurrency(float32(finalBalance)))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
|
}
|
|
}
|
|
|
|
// --- 8. Build response ---
|
|
res := &domain.AtlasBetWinResponse{
|
|
PlayerID: req.PlayerID,
|
|
Balance: finalBalance,
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *Service) ProcessRoundResult(ctx context.Context, req domain.RoundResultRequest) (*domain.RoundResultResponse, error) {
|
|
// --- 1. Validate required fields ---
|
|
if req.PlayerID == "" || req.TransactionID == "" {
|
|
return nil, fmt.Errorf("BAD_REQUEST: missing player_id or transaction_id")
|
|
}
|
|
|
|
// --- 2. Credit player if win amount > 0 ---
|
|
if req.Amount > 0 {
|
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("BAD_REQUEST: invalid playerID %q", req.PlayerID)
|
|
}
|
|
|
|
// --- 3. Fetch player wallet ---
|
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch wallet for player %d: %w", playerIDInt, err)
|
|
}
|
|
|
|
// --- 4. Convert balance and apply win amount ---
|
|
currentBalance := float64(wallet.RegularBalance.Float32())
|
|
newBalance := currentBalance + req.Amount
|
|
|
|
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.ToCurrency(float32(newBalance)))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
|
}
|
|
}
|
|
|
|
// --- 5. Build response ---
|
|
return &domain.RoundResultResponse{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Service) ProcessRollBack(ctx context.Context, req domain.RollbackRequest) (*domain.RollbackResponse, error) {
|
|
// --- 1. Validate required fields ---
|
|
if req.PlayerID == "" || req.BetTransactionID == "" {
|
|
return nil, fmt.Errorf("BAD_REQUEST: missing player_id or bet_transaction_id")
|
|
}
|
|
|
|
// --- 2. Parse PlayerID ---
|
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("BAD_REQUEST: invalid playerID %q", req.PlayerID)
|
|
}
|
|
|
|
// --- 3. Fetch player wallet ---
|
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch wallet for player %d: %w", playerIDInt, err)
|
|
}
|
|
|
|
// --- 4. Fetch original transfer ---
|
|
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)
|
|
}
|
|
|
|
// --- 5. Compute new balance using Float32() conversion ---
|
|
currentBalance := float64(wallet.RegularBalance.Float32())
|
|
newBalance := currentBalance + float64(transfer.Amount)
|
|
|
|
// --- 6. Credit player wallet ---
|
|
err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.ToCurrency(float32(newBalance)))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
|
}
|
|
|
|
// --- 7. Update transfer status and verification ---
|
|
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)
|
|
}
|
|
|
|
// --- 8. Build response ---
|
|
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")
|
|
}
|
|
|
|
if req.Amount <= 0 {
|
|
// No winnings to process
|
|
return &domain.FreeSpinResultResponse{Success: true}, nil
|
|
}
|
|
|
|
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 wallet 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)
|
|
}
|
|
|
|
// Optionally record the transaction in your transfer history for auditing
|
|
// _ = s.transfetStore.CreateGamePayoutTransfer(...)
|
|
|
|
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")
|
|
}
|
|
|
|
if req.Amount <= 0 {
|
|
// No jackpot winnings
|
|
return &domain.JackpotResponse{Success: true}, nil
|
|
}
|
|
|
|
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 wallet 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{
|
|
ReferenceNumber: domain.ValidString{
|
|
Value: req.TransactionID,
|
|
Valid: true,
|
|
},
|
|
// Description: fmt.Sprintf("Jackpot win - Txn: %s", req.TransactionID),
|
|
},
|
|
"",
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
|
}
|
|
|
|
return &domain.JackpotResponse{Success: true}, nil
|
|
}
|