458 lines
14 KiB
Go
458 lines
14 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
// "fmt"
|
|
"strings"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
|
"github.com/gofiber/fiber/v2"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// GetProviders godoc
|
|
// @Summary Get game providers
|
|
// @Description Retrieves the list of VeliGames providers
|
|
// @Tags Virtual Games - VeliGames
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.ProviderRequest true "Brand ID and paging options"
|
|
// @Success 200 {object} domain.Response{data=[]domain.ProviderResponse}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 401 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/veli/providers [post]
|
|
func (h *Handler) GetProviders(c *fiber.Ctx) error {
|
|
var req domain.ProviderRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Failed to retrieve providers",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
if req.BrandID == "" {
|
|
req.BrandID = h.Cfg.VeliGames.BrandID // default
|
|
}
|
|
res, err := h.veliVirtualGameSvc.GetProviders(context.Background(), req)
|
|
if err != nil {
|
|
h.InternalServerErrorLogger().Error("Failed to [VeliGameHandler]GetProviders",
|
|
zap.Any("request", req),
|
|
zap.Error(err),
|
|
)
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to retrieve providers",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Providers retrieved successfully",
|
|
Data: res,
|
|
StatusCode: 200,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
// GetGamesByProvider godoc
|
|
// @Summary Get games by provider
|
|
// @Description Retrieves games for the specified provider
|
|
// @Tags Virtual Games - VeliGames
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.GameListRequest true "Brand and Provider ID"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /api/v1/veli/games-list [post]
|
|
func (h *Handler) GetGamesByProvider(c *fiber.Ctx) error {
|
|
var req domain.GameListRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Default brand if not provided
|
|
if req.BrandID == "" {
|
|
req.BrandID = h.Cfg.VeliGames.BrandID
|
|
}
|
|
|
|
res, err := h.veliVirtualGameSvc.GetGames(context.Background(), req)
|
|
if err != nil {
|
|
h.InternalServerErrorLogger().Error("Failed to [VeliGameHandler]GetGames",
|
|
zap.Any("request", req),
|
|
zap.Error(err),
|
|
)
|
|
// Handle provider disabled case specifically
|
|
if strings.Contains(err.Error(), "is disabled") {
|
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
|
Message: "Provider is disabled",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Fallback for other errors
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to retrieve games",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Games retrieved successfully",
|
|
Data: res,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
// StartGame godoc
|
|
// @Summary Start a real game session
|
|
// @Description Starts a real VeliGames session with the given player and game info
|
|
// @Tags Virtual Games - VeliGames
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.GameStartRequest true "Start game input"
|
|
// @Success 200 {object} domain.Response{data=domain.GameStartResponse}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /api/v1/veli/start-game [post]
|
|
func (h *Handler) StartGame(c *fiber.Ctx) error {
|
|
// userId, ok := c.Locals("user_id").(int64)
|
|
// fmt.Printf("\n\nVeli Start Game User ID is %v\n\n", userId)
|
|
// if !ok {
|
|
// return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
// Error: "missing user id",
|
|
// Message: "Unauthorized",
|
|
// })
|
|
// }
|
|
|
|
var req domain.GameStartRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// There needs to be a way to generate a sessionID
|
|
|
|
// Attach user ID to request
|
|
// req.PlayerID = fmt.Sprintf("%d", userId)
|
|
|
|
// Default brand if not provided
|
|
if req.BrandID == "" {
|
|
req.BrandID = h.Cfg.VeliGames.BrandID
|
|
}
|
|
|
|
req.IP = c.IP()
|
|
|
|
res, err := h.veliVirtualGameSvc.StartGame(context.Background(), req)
|
|
if err != nil {
|
|
h.InternalServerErrorLogger().Error("Failed to [VeliGameHandler]StartGame",
|
|
zap.Any("request", req),
|
|
zap.Error(err),
|
|
)
|
|
// Handle provider disabled case specifically
|
|
if strings.Contains(err.Error(), "is disabled") {
|
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
|
Message: "Provider is disabled",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Fallback for other errors
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to start game",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Game started successfully",
|
|
Data: res,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
// StartDemoGame godoc
|
|
// @Summary Start a demo game session
|
|
// @Description Starts a demo session of the specified game (must support demo mode)
|
|
// @Tags Virtual Games - VeliGames
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.DemoGameRequest true "Start demo game input"
|
|
// @Success 200 {object} domain.Response{data=domain.GameStartResponse}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /api/v1/veli/start-demo-game [post]
|
|
func (h *Handler) StartDemoGame(c *fiber.Ctx) error {
|
|
var req domain.DemoGameRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Default brand if not provided
|
|
if req.BrandID == "" {
|
|
req.BrandID = h.Cfg.VeliGames.BrandID
|
|
}
|
|
|
|
req.IP = c.IP()
|
|
|
|
res, err := h.veliVirtualGameSvc.StartDemoGame(context.Background(), req)
|
|
if err != nil {
|
|
h.InternalServerErrorLogger().Error("Failed to [VeliGameHandler]StartDemoGame",
|
|
zap.Any("request", req),
|
|
zap.Error(err),
|
|
)
|
|
// Handle provider disabled case specifically
|
|
if strings.Contains(err.Error(), "is disabled") {
|
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
|
Message: "Provider is disabled",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Fallback for other errors
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to start demo game",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Demo game started successfully",
|
|
Data: res,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
func (h *Handler) GetBalance(c *fiber.Ctx) error {
|
|
var req domain.BalanceRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Optionally verify signature here...
|
|
|
|
balance, err := h.veliVirtualGameSvc.GetBalance(c.Context(), req)
|
|
if err != nil {
|
|
// return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Failed to retrieve balance",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(balance)
|
|
}
|
|
|
|
func (h *Handler) PlaceBet(c *fiber.Ctx) error {
|
|
var req domain.BetRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Signature check optional here
|
|
|
|
res, err := h.veliVirtualGameSvc.ProcessBet(c.Context(), req)
|
|
if err != nil {
|
|
if errors.Is(err, veli.ErrDuplicateTransaction) {
|
|
return fiber.NewError(fiber.StatusConflict, "DUPLICATE_TRANSACTION")
|
|
}
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process bet",
|
|
Error: err.Error(),
|
|
})
|
|
// return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
}
|
|
|
|
return c.JSON(res)
|
|
}
|
|
|
|
func (h *Handler) RegisterWin(c *fiber.Ctx) error {
|
|
var req domain.WinRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
res, err := h.veliVirtualGameSvc.ProcessWin(c.Context(), req)
|
|
if err != nil {
|
|
if errors.Is(err, veli.ErrDuplicateTransaction) {
|
|
return fiber.NewError(fiber.StatusConflict, "DUPLICATE_TRANSACTION")
|
|
}
|
|
// return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process win",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(res)
|
|
}
|
|
|
|
func (h *Handler) CancelTransaction(c *fiber.Ctx) error {
|
|
var req domain.CancelRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
res, err := h.veliVirtualGameSvc.ProcessCancel(c.Context(), req)
|
|
if err != nil {
|
|
if errors.Is(err, veli.ErrDuplicateTransaction) {
|
|
return fiber.NewError(fiber.StatusConflict, "DUPLICATE_TRANSACTION")
|
|
}
|
|
// return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process cancel",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// GetGamingActivity godoc
|
|
// @Summary Get Veli Gaming Activity
|
|
// @Description Retrieves successfully processed gaming activity transactions (BET, WIN, CANCEL) from Veli Games
|
|
// @Tags Virtual Games - VeliGames
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.GamingActivityRequest true "Gaming Activity Request"
|
|
// @Success 200 {object} domain.Response{data=domain.GamingActivityResponse}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/veli/gaming-activity [post]
|
|
func (h *Handler) GetGamingActivity(c *fiber.Ctx) error {
|
|
var req domain.GamingActivityRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request payload",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
resp, err := h.veliVirtualGameSvc.GetGamingActivity(c.Context(), req)
|
|
if err != nil {
|
|
h.InternalServerErrorLogger().Error("Failed to [VeliGameHandler]GetGamingActivity",
|
|
zap.Any("request", req),
|
|
zap.Error(err),
|
|
)
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to retrieve gaming activity",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Gaming activity retrieved successfully",
|
|
Data: resp,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
// GetHugeWins godoc
|
|
// @Summary Get Veli Huge Wins
|
|
// @Description Retrieves huge win transactions based on brand configuration (e.g. win > 10000 USD or 100x bet)
|
|
// @Tags Virtual Games - VeliGames
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.HugeWinsRequest true "Huge Wins Request"
|
|
// @Success 200 {object} domain.Response{data=domain.HugeWinsResponse}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/veli/huge-wins [post]
|
|
func (h *Handler) GetHugeWins(c *fiber.Ctx) error {
|
|
var req domain.HugeWinsRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request payload",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
resp, err := h.veliVirtualGameSvc.GetHugeWins(c.Context(), req)
|
|
if err != nil {
|
|
h.InternalServerErrorLogger().Error("Failed to [VeliGameHandler]GetHugeWins",
|
|
zap.Any("request", req),
|
|
zap.Error(err),
|
|
)
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to retrieve huge wins",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Huge wins retrieved successfully",
|
|
Data: resp,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
// GetCreditBalances godoc
|
|
// @Summary Get VeliGames credit balances for a brand
|
|
// @Description Fetches current credit balances per currency for the specified brand
|
|
// @Tags Virtual Games - VeliGames
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param brandId query string true "Brand ID"
|
|
// @Success 200 {object} domain.Response{data=[]domain.CreditBalance}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /api/v1/veli/credit-balances [get]
|
|
func (h *Handler) GetCreditBalances(c *fiber.Ctx) error {
|
|
brandID := c.Query("brandId", h.Cfg.VeliGames.BrandID) // Default brand if not provided
|
|
|
|
if brandID == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Brand ID is required",
|
|
Error: "missing brandId",
|
|
})
|
|
}
|
|
|
|
res, err := h.veliVirtualGameSvc.GetCreditBalances(c.Context(), brandID)
|
|
if err != nil {
|
|
h.InternalServerErrorLogger().Error("Failed to [VeliGameHandler]GetCreditBalances",
|
|
zap.String("brandID", brandID),
|
|
zap.Error(err),
|
|
)
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to fetch credit balances",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Credit balances fetched successfully",
|
|
Data: res,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|