package service import ( "context" "fmt" "apskel-pos-be/internal/models" "apskel-pos-be/internal/processor" "apskel-pos-be/internal/repository" "github.com/google/uuid" ) type SpinGameService interface { PlaySpinGame(ctx context.Context, customerID string, req *models.SpinGameRequest) (*models.SpinGameResponse, error) } type spinGameService struct { gamePlayProcessor *processor.GamePlayProcessor txManager *repository.TxManager } func NewSpinGameService(gamePlayProcessor *processor.GamePlayProcessor, txManager *repository.TxManager) SpinGameService { return &spinGameService{ gamePlayProcessor: gamePlayProcessor, txManager: txManager, } } func (s *spinGameService) PlaySpinGame(ctx context.Context, customerID string, req *models.SpinGameRequest) (*models.SpinGameResponse, error) { // Validate customer ID if customerID == "" { return nil, fmt.Errorf("customer ID is required") } // Parse spin ID to UUID spinID, err := uuid.Parse(req.SpinID) if err != nil { return nil, fmt.Errorf("invalid spin ID format: %w", err) } // Parse customer ID to UUID customerUUID, err := uuid.Parse(customerID) if err != nil { return nil, fmt.Errorf("invalid customer ID format: %w", err) } // Use transaction to ensure consistency var playResponse *models.PlayGameResponse err = s.txManager.WithTransaction(ctx, func(txCtx context.Context) error { // Create play game request playGameReq := &models.PlayGameRequest{ GameID: spinID, CustomerID: customerUUID, TokenUsed: 1, // Default to 1 token per spin } // Play the game within transaction var playErr error playResponse, playErr = s.gamePlayProcessor.PlayGame(txCtx, playGameReq) if playErr != nil { return fmt.Errorf("failed to play spin game: %w", playErr) } return nil }) if err != nil { return nil, err } // Convert prize to customer-facing format var customerPrize *models.CustomerGamePrizeResponse if playResponse.PrizeWon != nil { customerPrize = &models.CustomerGamePrizeResponse{ ID: playResponse.PrizeWon.ID, GameID: playResponse.PrizeWon.GameID, Name: playResponse.PrizeWon.Name, Image: playResponse.PrizeWon.Image, Metadata: &playResponse.PrizeWon.Metadata, CreatedAt: playResponse.PrizeWon.CreatedAt, UpdatedAt: playResponse.PrizeWon.UpdatedAt, } } // Convert to spin game response response := &models.SpinGameResponse{ Status: "SUCCESS", Message: "Spin game completed successfully.", Data: &models.SpinGameResponseData{ GamePlay: playResponse.GamePlay, PrizeWon: customerPrize, TokensRemaining: playResponse.TokensRemaining, }, } return response, nil }