package service import ( "context" "sno/internal/models" "sno/internal/repository" "sort" ) // UserService defines the interface for user-related business logic. type UserService interface { GetUserProfile(ctx context.Context, userID int64) (*models.User, error) GetOrCreateUser(ctx context.Context, telegramID int64, firstName, lastName, username, photoURL string) (*models.User, error) GetUserPurchases(ctx context.Context, userID int64) ([]models.Purchase, error) GetUserTransactions(ctx context.Context, userID int64) ([]models.Transaction, error) } // userService implements the UserService interface. type userService struct { userRepo repository.UserRepository purchaseRepo repository.PurchaseRepository quizAttemptRepo repository.QuizAttemptRepository } // NewUserService creates a new instance of a user service. func NewUserService(userRepo repository.UserRepository, purchaseRepo repository.PurchaseRepository, quizAttemptRepo repository.QuizAttemptRepository) UserService { return &userService{userRepo: userRepo, purchaseRepo: purchaseRepo, quizAttemptRepo: quizAttemptRepo} } // GetUserProfile retrieves the user's profile. func (s *userService) GetUserProfile(ctx context.Context, userID int64) (*models.User, error) { return s.userRepo.GetByID(ctx, userID) } // GetOrCreateUser retrieves an existing user or creates a new one func (s *userService) GetOrCreateUser(ctx context.Context, telegramID int64, firstName, lastName, username, photoURL string) (*models.User, error) { // Try to get existing user first user, err := s.userRepo.GetByID(ctx, telegramID) if err == nil { return user, nil } // If user not found, create new one newUser := &models.User{ TelegramID: telegramID, FirstName: &firstName, LastName: &lastName, Username: &username, StarsBalance: 0, } // Add photo URL if provided if photoURL != "" { newUser.PhotoURL = &photoURL } if err := s.userRepo.CreateUser(ctx, newUser); err != nil { return nil, err } return newUser, nil } // GetUserPurchases retrieves the user's purchase history. func (s *userService) GetUserPurchases(ctx context.Context, userID int64) ([]models.Purchase, error) { return s.purchaseRepo.GetByUserID(ctx, userID) } // GetUserTransactions retrieves a unified list of all user transactions (earned and spent). func (s *userService) GetUserTransactions(ctx context.Context, userID int64) ([]models.Transaction, error) { var transactions []models.Transaction // Get purchases (spent) purchases, err := s.purchaseRepo.GetByUserID(ctx, userID) if err != nil { return nil, err } for _, p := range purchases { transactions = append(transactions, models.Transaction{ Type: models.TransactionSpent, Amount: p.StarsSpent, Description: "Покупка приза", CreatedAt: p.PurchasedAt, }) } // Get quiz attempts (earned) attempts, err := s.quizAttemptRepo.GetByUserID(ctx, userID) if err != nil { return nil, err } for _, a := range attempts { if a.StarsEarned > 0 { transactions = append(transactions, models.Transaction{ Type: models.TransactionEarned, Amount: a.StarsEarned, Description: "Награда за викторину", CreatedAt: a.CompletedAt, }) } } // Sort transactions by date descending sort.Slice(transactions, func(i, j int) bool { return transactions[i].CreatedAt.After(transactions[j].CreatedAt) }) return transactions, nil }