Yimaru-BackEnd/internal/services/virtualGame/veli/game_orchestration.go

295 lines
8.7 KiB
Go

package veli
import (
"context"
"fmt"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5/pgtype"
"go.uber.org/zap"
)
func (s *Service) AddProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error) {
logger := s.mongoLogger.With(zap.String("service", "AddProviders"), zap.Any("ProviderRequest", req))
// 0. Remove all existing providers first
if err := s.repo.DeleteAllVirtualGameProviders(ctx); err != nil {
logger.Error("failed to delete all virtual game providers", zap.Error(err))
return nil, fmt.Errorf("failed to clear existing providers: %w", err)
}
// 1. Prepare signature parameters
sigParams := map[string]any{
"brandId": req.BrandID,
}
// Optional fields
sigParams["extraData"] = fmt.Sprintf("%t", req.ExtraData) // false is still included
if req.Size > 0 {
sigParams["size"] = fmt.Sprintf("%d", req.Size)
} else {
sigParams["size"] = ""
}
if req.Page > 0 {
sigParams["page"] = fmt.Sprintf("%d", req.Page)
} else {
sigParams["page"] = ""
}
// 2. Call external API
var res domain.ProviderResponse
if err := s.client.post(ctx, "/game-lists/public/providers", req, sigParams, &res); err != nil {
return nil, fmt.Errorf("failed to fetch providers: %w", err)
}
// 3. Loop through fetched providers and insert into DB
for _, p := range res.Items {
createParams := dbgen.CreateVirtualGameProviderParams{
ProviderID: p.ProviderID,
ProviderName: p.ProviderName,
LogoDark: pgtype.Text{String: p.LogoForDark, Valid: p.LogoForDark != ""},
LogoLight: pgtype.Text{String: p.LogoForLight, Valid: p.LogoForLight != ""},
Enabled: true,
}
if _, err := s.repo.CreateVirtualGameProvider(ctx, createParams); err != nil {
logger.Error("failed to add provider", zap.Error(err))
return nil, fmt.Errorf("failed to add provider %s: %w", p.ProviderID, err)
}
}
// 4. Always add "popok" provider manually
popokParams := dbgen.CreateVirtualGameProviderParams{
ProviderID: "popok",
ProviderName: "Popok Gaming",
LogoDark: pgtype.Text{String: fmt.Sprintf("%v/static/logos/popok-dark.png", s.cfg.PopOK.CallbackURL), Valid: true}, // adjust as needed
LogoLight: pgtype.Text{String: fmt.Sprintf("%v/static/logos/popok-light.png", s.cfg.PopOK.CallbackURL), Valid: true}, // adjust as needed
Enabled: true,
}
atlasParams := dbgen.CreateVirtualGameProviderParams{
ProviderID: "atlas",
ProviderName: "Atlas Gaming",
LogoDark: pgtype.Text{String: "/static/logos/atlas-dark.png", Valid: true}, // adjust as needed
LogoLight: pgtype.Text{String: "/static/logos/atlas-light.png", Valid: true}, // adjust as needed
Enabled: true,
}
if _, err := s.repo.CreateVirtualGameProvider(ctx, popokParams); err != nil {
logger.Error("failed to add popok provider", zap.Any("popokParams", popokParams), zap.Error(err))
return nil, fmt.Errorf("failed to add popok provider: %w", err)
}
if _, err := s.repo.CreateVirtualGameProvider(ctx, atlasParams); err != nil {
return nil, fmt.Errorf("failed to add atlas provider: %w", err)
}
// Optionally also append it to the response for consistency
// res.Items = append(res.Items, domain.VirtualGameProvider{
// ProviderID: uuid.New().String(),
// ProviderName: "Popok Gaming",
// LogoForDark: "/static/logos/popok-dark.png",
// LogoForLight: "/static/logos/popok-light.png",
// })
return &res, nil
}
func (s *Service) GetAllVirtualGames(ctx context.Context, params dbgen.GetAllVirtualGamesParams) ([]domain.UnifiedGame, error) {
// Build params for repo call
logger := s.mongoLogger.With(zap.String("service", "GetAllVirtualGames"), zap.Any("params", params))
rows, err := s.repo.ListAllVirtualGames(ctx, params)
if err != nil {
logger.Error("[GetAllVirtualGames] Failed to fetch virtual games", zap.Error(err))
return nil, fmt.Errorf("failed to fetch virtual games: %w", err)
}
var allGames []domain.UnifiedGame
for _, r := range rows {
// --- Convert nullable Rtp to *float64 ---
var rtpPtr *float64
if r.Rtp.Valid {
rtpFloat, err := r.Rtp.Float64Value()
if err == nil {
rtpPtr = new(float64)
*rtpPtr = rtpFloat.Float64
}
}
var betsFloat64 []float64
for _, bet := range r.Bets {
if bet.Valid {
betFloat, err := bet.Float64Value()
if err == nil {
betsFloat64 = append(betsFloat64, betFloat.Float64)
}
}
}
allGames = append(allGames, domain.UnifiedGame{
GameID: r.GameID,
ProviderID: r.ProviderID,
Provider: r.ProviderName,
Name: r.Name,
Category: r.Category.String,
DeviceType: r.DeviceType.String,
Volatility: r.Volatility.String,
RTP: rtpPtr,
HasDemo: r.HasDemo.Bool,
HasFreeBets: r.HasFreeBets.Bool,
Bets: betsFloat64,
Thumbnail: r.Thumbnail.String,
Status: int(r.Status.Int32), // nullable status
})
}
return allGames, nil
}
func (s *Service) FetchAndStoreAllVirtualGames(ctx context.Context, req domain.ProviderRequest, currency string) ([]domain.UnifiedGame, error) {
logger := s.mongoLogger.With(
zap.String("service", "FetchAndStoreAllVirtualGames"),
zap.Any("ProviderRequest", req),
)
// This is necessary, since the provider is a foreign key
_, err := s.AddProviders(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to add providers to database: %w", err)
}
var allGames []domain.UnifiedGame
// --- 1. Get providers from external API ---
providersRes, err := s.GetProviders(ctx, req)
if err != nil {
logger.Error("Failed to fetch provider", zap.Error(err))
return nil, fmt.Errorf("failed to fetch providers: %w", err)
}
// --- 2. Fetch games for each provider ---
for _, p := range providersRes.Items {
// Violates foreign key if the provider isn't added
games, err := s.GetGames(ctx, domain.GameListRequest{
BrandID: s.cfg.VeliGames.BrandID,
ProviderID: p.ProviderID,
Page: req.Page,
Size: req.Size,
})
if err != nil {
logger.Error("failed to get veli games", zap.String("ProviderID", p.ProviderID), zap.Error(err))
continue // skip failing provider but continue others
}
for _, g := range games {
unified := domain.UnifiedGame{
GameID: g.GameID,
ProviderID: g.ProviderID,
Provider: p.ProviderName,
Name: g.Name,
Category: g.Category,
DeviceType: g.DeviceType,
// Volatility: g.Volatility,
// RTP: g.RTP,
HasDemo: g.HasDemoMode,
HasFreeBets: g.HasFreeBets,
}
allGames = append(allGames, unified)
// --- Save to DB ---
_, err = s.repo.CreateVirtualGame(ctx, dbgen.CreateVirtualGameParams{
GameID: g.GameID,
ProviderID: g.ProviderID,
Name: g.Name,
Category: pgtype.Text{
String: g.Category,
Valid: g.Category != "",
},
DeviceType: pgtype.Text{
String: g.DeviceType,
Valid: g.DeviceType != "",
},
// Volatility: g.Volatility,
// RTP: g.RTP,
HasDemo: pgtype.Bool{
Bool: g.HasDemoMode,
Valid: true,
},
HasFreeBets: pgtype.Bool{
Bool: g.HasFreeBets,
Valid: true,
},
// Bets: g.Bets,
// Thumbnail: g.Thumbnail,
// Status: g.Status,
})
if err != nil {
logger.Error("failed to create virtual game", zap.Error(err))
}
}
}
// --- 3. Handle PopOK separately ---
popokGames, err := s.virtualGameSvc.ListGames(ctx, currency)
if err != nil {
logger.Error("failed to fetch PopOk games", zap.Error(err))
return nil, fmt.Errorf("failed to fetch PopOK games: %w", err)
}
for _, g := range popokGames {
unified := domain.UnifiedGame{
GameID: fmt.Sprintf("%d", g.ID),
ProviderID: "popok",
Provider: "PopOK",
Name: g.GameName,
Category: "Crash",
Bets: g.Bets,
Thumbnail: g.Thumbnail,
Status: g.Status,
}
allGames = append(allGames, unified)
// --- Convert []float64 to []pgtype.Numeric ---
var betsNumeric []pgtype.Numeric
for _, bet := range g.Bets {
var num pgtype.Numeric
_ = num.Scan(bet)
betsNumeric = append(betsNumeric, num)
}
// --- Save to DB ---
_, err = s.repo.CreateVirtualGame(ctx, dbgen.CreateVirtualGameParams{
GameID: fmt.Sprintf("%d", g.ID), //The id here needs to be clean for me to access
ProviderID: "popok",
Name: g.GameName,
Bets: betsNumeric,
Thumbnail: pgtype.Text{
String: g.Thumbnail,
Valid: g.Thumbnail != "",
},
Status: pgtype.Int4{
Int32: int32(g.Status),
Valid: true,
},
HasDemo: pgtype.Bool{
Bool: true,
Valid: true,
},
Category: pgtype.Text{
String: "Crash",
Valid: true,
},
})
if err != nil {
logger.Error("failed to create virtual game", zap.Error(err))
}
}
return allGames, nil
}