package repository import ( "context" "database/sql" "errors" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/jackc/pgx/v5/pgtype" ) type VirtualGameRepository interface { CountVirtualGameProviders(ctx context.Context) (int64, error) CreateVirtualGameProvider(ctx context.Context, arg dbgen.CreateVirtualGameProviderParams) (dbgen.VirtualGameProvider, error) DeleteVirtualGameProvider(ctx context.Context, providerID string) error DeleteAllVirtualGameProviders(ctx context.Context) error GetVirtualGameProviderByID(ctx context.Context, providerID string) (dbgen.VirtualGameProvider, error) ListVirtualGameProviders(ctx context.Context, limit, offset int32) ([]dbgen.VirtualGameProvider, error) UpdateVirtualGameProviderEnabled(ctx context.Context, providerID string, enabled bool) (dbgen.VirtualGameProvider, error) CreateVirtualGameSession(ctx context.Context, session *domain.VirtualGameSession) error GetVirtualGameSessionByToken(ctx context.Context, token string) (*domain.VirtualGameSession, error) UpdateVirtualGameSessionStatus(ctx context.Context, id int64, status string) error CreateVirtualGameTransaction(ctx context.Context, tx *domain.VirtualGameTransaction) error GetVirtualGameTransactionByExternalID(ctx context.Context, externalID string) (*domain.VirtualGameTransaction, error) UpdateVirtualGameTransactionStatus(ctx context.Context, id int64, status string) error // WithTransaction(ctx context.Context, fn func(ctx context.Context) error) error AddFavoriteGame(ctx context.Context, userID, gameID int64) error RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error ListFavoriteGames(ctx context.Context, userID int64) ([]int64, error) // GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) GetUserGameHistory(ctx context.Context, userID int64) ([]domain.VirtualGameHistory, error) CreateVirtualGameHistory(ctx context.Context, his *domain.VirtualGameHistory) error CreateVirtualGame(ctx context.Context, arg dbgen.CreateVirtualGameParams) (dbgen.VirtualGame, error) ListAllVirtualGames(ctx context.Context, arg dbgen.GetAllVirtualGamesParams) ([]dbgen.GetAllVirtualGamesRow, error) RemoveAllVirtualGames(ctx context.Context) error } type VirtualGameRepo struct { store *Store } // GetGameCounts implements VirtualGameRepository. // func (r *VirtualGameRepo) GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total int64, active int64, inactive int64, err error) { // panic("unimplemented") // } // func convertDBVirtualGameProvider(p dbgen.VirtualGameProvider) domain.VirtualGameProvider { // var logoDark *string // if p.LogoDark.Valid { // logoDark = &p.LogoDark.String // } // var logoLight *string // if p.LogoLight.Valid { // logoLight = &p.LogoLight.String // } // return domain.VirtualGameProvider{ // // ID: p.ID, // ProviderID: p.ProviderID, // ProviderName: p.ProviderName, // LogoDark: logoDark, // LogoLight: logoLight, // Enabled: p.Enabled, // CreatedAt: p.CreatedAt.Time, // UpdatedAt: &p.UpdatedAt.Time, // } // } func ConvertCreateVirtualGameProvider(p domain.VirtualGameProvider) dbgen.CreateVirtualGameProviderParams { return dbgen.CreateVirtualGameProviderParams{ ProviderID: p.ProviderID, ProviderName: p.ProviderName, LogoDark: pgtype.Text{String: func() string { if p.LogoDark != nil { return *p.LogoDark } return "" }(), Valid: p.LogoDark != nil}, LogoLight: pgtype.Text{String: func() string { if p.LogoLight != nil { return *p.LogoLight } return "" }(), Valid: p.LogoLight != nil}, Enabled: p.Enabled, // CreatedAt: time.Now(), } } func NewVirtualGameRepository(store *Store) VirtualGameRepository { return &VirtualGameRepo{store: store} } func (r *VirtualGameRepo) CreateVirtualGameProvider(ctx context.Context, arg dbgen.CreateVirtualGameProviderParams) (dbgen.VirtualGameProvider, error) { return r.store.queries.CreateVirtualGameProvider(ctx, arg) } func (r *VirtualGameRepo) RemoveVirtualGameProvider(ctx context.Context, providerID string) error { return r.store.queries.DeleteVirtualGameProvider(ctx, providerID) } func (r *VirtualGameRepo) DeleteAllVirtualGameProviders(ctx context.Context) error { return r.store.queries.DeleteAllVirtualGameProviders(ctx) } func (r *VirtualGameRepo) DeleteVirtualGameProvider(ctx context.Context, providerID string) error { return r.store.queries.DeleteVirtualGameProvider(ctx, providerID) } func (r *VirtualGameRepo) GetVirtualGameProviderByID(ctx context.Context, providerID string) (dbgen.VirtualGameProvider, error) { return r.store.queries.GetVirtualGameProviderByID(ctx, providerID) } func (r *VirtualGameRepo) ListVirtualGameProviders(ctx context.Context, limit, offset int32) ([]dbgen.VirtualGameProvider, error) { args := dbgen.ListVirtualGameProvidersParams{ Limit: limit, Offset: offset, } return r.store.queries.ListVirtualGameProviders(ctx, args) } func (r *VirtualGameRepo) UpdateVirtualGameProviderEnabled(ctx context.Context, providerID string, enabled bool) (dbgen.VirtualGameProvider, error) { params := dbgen.UpdateVirtualGameProviderEnabledParams{ ProviderID: providerID, Enabled: enabled, } return r.store.queries.UpdateVirtualGameProviderEnabled(ctx, params) } func (r *VirtualGameRepo) AddFavoriteGame(ctx context.Context, userID, gameID int64) error { params := dbgen.AddFavoriteGameParams{ UserID: userID, GameID: gameID, } return r.store.queries.AddFavoriteGame(ctx, params) } func (r *VirtualGameRepo) RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error { params := dbgen.RemoveFavoriteGameParams{ UserID: userID, GameID: gameID, } return r.store.queries.RemoveFavoriteGame(ctx, params) } func (r *VirtualGameRepo) ListFavoriteGames(ctx context.Context, userID int64) ([]int64, error) { return r.store.queries.ListFavoriteGames(ctx, userID) } func (r *VirtualGameRepo) CountVirtualGameProviders(ctx context.Context) (int64, error) { return r.store.queries.CountVirtualGameProviders(ctx) } func (r *VirtualGameRepo) CreateVirtualGameSession(ctx context.Context, session *domain.VirtualGameSession) error { params := dbgen.CreateVirtualGameSessionParams{ UserID: session.UserID, GameID: session.GameID, SessionToken: session.SessionToken, Currency: session.Currency, Status: session.Status, ExpiresAt: pgtype.Timestamptz{Time: session.ExpiresAt, Valid: true}, } _, err := r.store.queries.CreateVirtualGameSession(ctx, params) return err } func (r *VirtualGameRepo) GetVirtualGameSessionByToken(ctx context.Context, token string) (*domain.VirtualGameSession, error) { dbSession, err := r.store.queries.GetVirtualGameSessionByToken(ctx, token) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } return nil, err } return &domain.VirtualGameSession{ ID: dbSession.ID, UserID: dbSession.UserID, GameID: dbSession.GameID, SessionToken: dbSession.SessionToken, Currency: dbSession.Currency, Status: dbSession.Status, CreatedAt: dbSession.CreatedAt.Time, UpdatedAt: dbSession.UpdatedAt.Time, ExpiresAt: dbSession.ExpiresAt.Time, }, nil } func (r *VirtualGameRepo) UpdateVirtualGameSessionStatus(ctx context.Context, id int64, status string) error { return r.store.queries.UpdateVirtualGameSessionStatus(ctx, dbgen.UpdateVirtualGameSessionStatusParams{ ID: id, Status: status, }) } func (r *VirtualGameRepo) CreateVirtualGameTransaction(ctx context.Context, tx *domain.VirtualGameTransaction) error { params := dbgen.CreateVirtualGameTransactionParams{ SessionID: tx.SessionID, UserID: tx.UserID, WalletID: tx.WalletID, TransactionType: tx.TransactionType, Amount: tx.Amount, Currency: tx.Currency, ExternalTransactionID: tx.ExternalTransactionID, Status: tx.Status, } _, err := r.store.queries.CreateVirtualGameTransaction(ctx, params) return err } func (r *VirtualGameRepo) CreateVirtualGameHistory(ctx context.Context, his *domain.VirtualGameHistory) error { params := dbgen.CreateVirtualGameHistoryParams{ SessionID: pgtype.Text{String: his.SessionID, Valid: true}, UserID: his.UserID, // WalletID: pgtype.Int8{Int64: *his.WalletID, Valid: true}, TransactionType: his.TransactionType, Amount: his.Amount, Currency: his.Currency, ExternalTransactionID: his.ExternalTransactionID, Status: his.Status, } _, err := r.store.queries.CreateVirtualGameHistory(ctx, params) return err } func (r *VirtualGameRepo) GetVirtualGameTransactionByExternalID(ctx context.Context, externalID string) (*domain.VirtualGameTransaction, error) { dbTx, err := r.store.queries.GetVirtualGameTransactionByExternalID(ctx, externalID) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } return nil, err } return &domain.VirtualGameTransaction{ ID: dbTx.ID, SessionID: dbTx.SessionID, UserID: dbTx.UserID, WalletID: dbTx.WalletID, TransactionType: dbTx.TransactionType, Amount: dbTx.Amount, Currency: dbTx.Currency, ExternalTransactionID: dbTx.ExternalTransactionID, Status: dbTx.Status, CreatedAt: dbTx.CreatedAt.Time, UpdatedAt: dbTx.UpdatedAt.Time, }, nil } func (r *VirtualGameRepo) UpdateVirtualGameTransactionStatus(ctx context.Context, id int64, status string) error { return r.store.queries.UpdateVirtualGameTransactionStatus(ctx, dbgen.UpdateVirtualGameTransactionStatusParams{ ID: id, Status: status, }) } // func (r *VirtualGameRepo) GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) { // query := `SELECT // COUNT(*) as total, // COUNT(CASE WHEN is_active = true THEN 1 END) as active, // COUNT(CASE WHEN is_active = false THEN 1 END) as inactive // FROM virtual_games` // args := []interface{}{} // argPos := 1 // // Add filters if provided // if filter.StartTime.Valid { // query += fmt.Sprintf(" WHERE created_at >= $%d", argPos) // args = append(args, filter.StartTime.Value) // argPos++ // } // if filter.EndTime.Valid { // query += fmt.Sprintf(" AND created_at <= $%d", argPos) // args = append(args, filter.EndTime.Value) // argPos++ // } // row := r.store.conn.QueryRow(ctx, query, args...) // err = row.Scan(&total, &active, &inactive) // if err != nil { // return 0, 0, 0, fmt.Errorf("failed to get game counts: %w", err) // } // return total, active, inactive, nil // } func (r *VirtualGameRepo) GetUserGameHistory(ctx context.Context, userID int64) ([]domain.VirtualGameHistory, error) { query := `SELECT game_id FROM virtual_game_histories WHERE user_id = $1 AND transaction_type = 'BET' ORDER BY created_at DESC LIMIT 100` rows, err := r.store.conn.Query(ctx, query, userID) if err != nil { return nil, err } defer rows.Close() var history []domain.VirtualGameHistory for rows.Next() { var tx domain.VirtualGameHistory if err := rows.Scan(&tx.GameID); err == nil { history = append(history, tx) } } return history, nil } func (r *VirtualGameRepo) CreateVirtualGame(ctx context.Context, arg dbgen.CreateVirtualGameParams) (dbgen.VirtualGame, error) { return r.store.queries.CreateVirtualGame(ctx, arg) } func (r *VirtualGameRepo) ListAllVirtualGames(ctx context.Context, arg dbgen.GetAllVirtualGamesParams) ([]dbgen.GetAllVirtualGamesRow, error) { return r.store.queries.GetAllVirtualGames(ctx, arg) } func (r *VirtualGameRepo) RemoveAllVirtualGames(ctx context.Context) error { return r.store.queries.DeleteAllVirtualGames(ctx) }