package processor import ( "apskel-pos-be/internal/mappers" "apskel-pos-be/internal/models" "apskel-pos-be/internal/repository" "context" "fmt" ) type VoucherProcessor struct { voucherRepo *repository.VoucherRepository } func NewVoucherProcessor(voucherRepo *repository.VoucherRepository) *VoucherProcessor { return &VoucherProcessor{ voucherRepo: voucherRepo, } } // GetRandomVouchersForSpin retrieves random vouchers for spin feature func (p *VoucherProcessor) GetRandomVouchersForSpin(ctx context.Context, req *models.ListVouchersForSpinRequest) (*models.ListVouchersForSpinResponse, error) { // Set default limit if not provided limit := req.Limit if limit <= 0 { limit = 10 // Default limit } if limit > 50 { limit = 50 // Max limit } // Get random vouchers from repository vouchers, err := p.voucherRepo.GetRandomVouchers(ctx, limit) if err != nil { return nil, fmt.Errorf("failed to get random vouchers: %w", err) } // Convert to spin response format voucherResponses := make([]models.VoucherSpinResponse, len(vouchers)) for i, voucher := range vouchers { voucherResponses[i] = *mappers.VoucherEntityToSpinResponse(&voucher) } return &models.ListVouchersForSpinResponse{ Vouchers: voucherResponses, Count: len(voucherResponses), }, nil } // GetVoucherByID retrieves a voucher by ID func (p *VoucherProcessor) GetVoucherByID(ctx context.Context, voucherID int64) (*models.VoucherResponse, error) { voucher, err := p.voucherRepo.GetByID(ctx, voucherID) if err != nil { return nil, fmt.Errorf("voucher not found: %w", err) } return mappers.VoucherEntityToResponse(voucher), nil } // GetVoucherByCode retrieves a voucher by voucher code func (p *VoucherProcessor) GetVoucherByCode(ctx context.Context, voucherCode string) (*models.VoucherResponse, error) { voucher, err := p.voucherRepo.GetByVoucherCode(ctx, voucherCode) if err != nil { return nil, fmt.Errorf("voucher not found: %w", err) } return mappers.VoucherEntityToResponse(voucher), nil } // ListVouchers retrieves vouchers with pagination func (p *VoucherProcessor) ListVouchers(ctx context.Context, page, limit int) (*models.PaginatedVoucherResponse, error) { offset := (page - 1) * limit vouchers, total, err := p.voucherRepo.List(ctx, offset, limit) if err != nil { return nil, fmt.Errorf("failed to list vouchers: %w", err) } // Convert to response format voucherResponses := make([]models.VoucherResponse, len(vouchers)) for i, voucher := range vouchers { voucherResponses[i] = *mappers.VoucherEntityToResponse(&voucher) } totalPages := int((total + int64(limit) - 1) / int64(limit)) return &models.PaginatedVoucherResponse{ Data: voucherResponses, TotalCount: int(total), Page: page, Limit: limit, TotalPages: totalPages, }, nil } // GetRandomVouchersByRows retrieves random vouchers organized into rows func (p *VoucherProcessor) GetRandomVouchersByRows(ctx context.Context, req *models.ListVouchersByRowsRequest) (*models.ListVouchersByRowsResponse, error) { // Set default values if not provided rows := req.Rows if rows <= 0 { rows = 4 // Default to 4 rows } if rows > 10 { rows = 10 // Max 10 rows } // Get random vouchers organized by rows voucherRows, err := p.voucherRepo.GetRandomVouchersByRows(ctx, rows, req.WinnerNumber) if err != nil { return nil, fmt.Errorf("failed to get random vouchers by rows: %w", err) } // Convert to response format and select winners responseRows := make([]models.VoucherRow, len(voucherRows)) totalVouchers := 0 for i, row := range voucherRows { vouchers := make([]models.VoucherSpinResponse, len(row)) // Select a winner from this row if there are vouchers if len(row) > 0 { var winnerIndex int if req.WinnerNumber != nil { // If winner_number is specified, try to find a voucher with that winner_number // that is not already a winner, otherwise select any non-winner winnerIndex = -1 for j, voucher := range row { if voucher.WinnerNumber == *req.WinnerNumber && !voucher.IsWinner { winnerIndex = j break } } // If no voucher with specified winner_number found, select any non-winner if winnerIndex == -1 { for j, voucher := range row { if !voucher.IsWinner { winnerIndex = j break } } } // If still no non-winner found, select any voucher if winnerIndex == -1 { winnerIndex = 0 } } else { // If no winner_number specified, select any non-winner, otherwise any voucher winnerIndex = -1 for j, voucher := range row { if !voucher.IsWinner { winnerIndex = j break } } if winnerIndex == -1 { winnerIndex = 0 } } // Mark as winner in database if not already a winner if !row[winnerIndex].IsWinner { err := p.voucherRepo.MarkAsWinner(ctx, row[winnerIndex].ID) if err != nil { // Log error but continue - don't fail the entire request fmt.Printf("Failed to mark voucher %d as winner: %v\n", row[winnerIndex].ID, err) } else { // Update the voucher object to reflect the change row[winnerIndex].IsWinner = true } } } // Convert all vouchers to response format for j, voucher := range row { vouchers[j] = *mappers.VoucherEntityToSpinResponse(&voucher) } responseRows[i] = models.VoucherRow{ RowNumber: i + 1, // Row numbers start from 1 Vouchers: vouchers, } totalVouchers += len(row) } return &models.ListVouchersByRowsResponse{ Rows: responseRows, TotalRows: len(responseRows), TotalVouchers: totalVouchers, }, nil }