326 lines
11 KiB
Go
326 lines
11 KiB
Go
package handlers
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
type launchVirtualGameReq struct {
|
|
GameID string `json:"game_id" validate:"required" example:"crash_001"`
|
|
Currency string `json:"currency" validate:"required,len=3" example:"USD"`
|
|
Mode string `json:"mode" validate:"required,oneof=fun real" example:"real"`
|
|
}
|
|
|
|
type launchVirtualGameRes struct {
|
|
LaunchURL string `json:"launch_url"`
|
|
}
|
|
|
|
// LaunchVirtualGame godoc
|
|
// @Summary Launch a PopOK virtual game
|
|
// @Description Generates a URL to launch a PopOK game
|
|
// @Tags Virtual Games - PopOK
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security Bearer
|
|
// @Param launch body launchVirtualGameReq true "Game launch details"
|
|
// @Success 200 {object} launchVirtualGameRes
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 401 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /virtual-game/launch [post]
|
|
func (h *Handler) LaunchVirtualGame(c *fiber.Ctx) error {
|
|
|
|
userID, ok := c.Locals("user_id").(int64)
|
|
if !ok || userID == 0 {
|
|
h.logger.Error("Invalid user ID in context")
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
|
|
}
|
|
|
|
// companyID, ok := c.Locals("company_id").(int64)
|
|
// if !ok || companyID == 0 {
|
|
// h.logger.Error("Invalid company ID in context")
|
|
// return fiber.NewError(fiber.StatusUnauthorized, "Invalid company identification")
|
|
// }
|
|
|
|
var req launchVirtualGameReq
|
|
if err := c.BodyParser(&req); err != nil {
|
|
h.logger.Error("Failed to parse LaunchVirtualGame request", "error", err)
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
|
}
|
|
|
|
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
|
}
|
|
|
|
url, err := h.virtualGameSvc.GenerateGameLaunchURL(c.Context(), userID, req.GameID, req.Currency, req.Mode)
|
|
if err != nil {
|
|
h.logger.Error("Failed to generate game launch URL", "userID", userID, "gameID", req.GameID, "error", err)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to launch game")
|
|
}
|
|
|
|
res := launchVirtualGameRes{LaunchURL: url}
|
|
return response.WriteJSON(c, fiber.StatusOK, "Game launched successfully", res, nil)
|
|
}
|
|
|
|
// HandleVirtualGameCallback godoc
|
|
// @Summary Handle PopOK game callback
|
|
// @Description Processes callbacks from PopOK for game events
|
|
// @Tags Virtual Games - PopOK
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param callback body domain.PopOKCallback true "Callback data"
|
|
// @Success 200 {object} domain.ErrorResponse
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /virtual-game/callback [post]
|
|
func (h *Handler) HandleVirtualGameCallback(c *fiber.Ctx) error {
|
|
var callback domain.PopOKCallback
|
|
if err := c.BodyParser(&callback); err != nil {
|
|
h.logger.Error("Failed to parse callback", "error", err)
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid callback data")
|
|
}
|
|
|
|
if err := h.virtualGameSvc.HandleCallback(c.Context(), &callback); err != nil {
|
|
h.logger.Error("Failed to handle callback", "transactionID", callback.TransactionID, "error", err)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to process callback")
|
|
}
|
|
|
|
return response.WriteJSON(c, fiber.StatusOK, "Callback processed successfully", nil, nil)
|
|
}
|
|
|
|
func (h *Handler) HandlePlayerInfo(c *fiber.Ctx) error {
|
|
var req domain.PopOKPlayerInfoRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
|
}
|
|
|
|
resp, err := h.virtualGameSvc.GetPlayerInfo(c.Context(), &req)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(resp)
|
|
}
|
|
|
|
func (h *Handler) HandleBet(c *fiber.Ctx) error {
|
|
var req domain.PopOKBetRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid bet request")
|
|
}
|
|
|
|
resp, _ := h.virtualGameSvc.ProcessBet(c.Context(), &req)
|
|
// if err != nil {
|
|
// code := fiber.StatusInternalServerError
|
|
// // if err.Error() == "invalid token" {
|
|
// // code = fiber.StatusUnauthorized
|
|
// // } else if err.Error() == "insufficient balance" {
|
|
// // code = fiber.StatusBadRequest
|
|
// // }
|
|
// return fiber.NewError(code, err.Error())
|
|
// }
|
|
|
|
return response.WriteJSON(c, fiber.StatusOK, "Bet processed", resp, nil)
|
|
}
|
|
|
|
func (h *Handler) HandleWin(c *fiber.Ctx) error {
|
|
var req domain.PopOKWinRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid win request")
|
|
}
|
|
|
|
resp, _ := h.virtualGameSvc.ProcessWin(c.Context(), &req)
|
|
// if err != nil {
|
|
// code := fiber.StatusInternalServerError
|
|
// if err.Error() == "invalid token" {
|
|
// code = fiber.StatusUnauthorized
|
|
// }
|
|
// return fiber.NewError(code, err.Error())
|
|
// }
|
|
|
|
return response.WriteJSON(c, fiber.StatusOK, "Win processed", resp, nil)
|
|
}
|
|
|
|
func (h *Handler) HandleCancel(c *fiber.Ctx) error {
|
|
var req domain.PopOKCancelRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid cancel request")
|
|
}
|
|
|
|
resp, _ := h.virtualGameSvc.ProcessCancel(c.Context(), &req)
|
|
// if err != nil {
|
|
// code := fiber.StatusInternalServerError
|
|
// switch err.Error() {
|
|
// case "invalid token":
|
|
// code = fiber.StatusUnauthorized
|
|
// case "original bet not found", "invalid original transaction":
|
|
// code = fiber.StatusBadRequest
|
|
// }
|
|
// return fiber.NewError(code, err.Error())
|
|
// }
|
|
|
|
return response.WriteJSON(c, fiber.StatusOK, "Cancel processed", resp, nil)
|
|
}
|
|
|
|
// GetGameList godoc
|
|
// @Summary Get PopOK Games List
|
|
// @Description Retrieves the list of available PopOK slot games
|
|
// @Tags Virtual Games - PopOK
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param currency query string false "Currency (e.g. USD, ETB)" default(USD)
|
|
// @Success 200 {array} domain.PopOKGame
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /popok/games [get]
|
|
func (h *Handler) GetGameList(c *fiber.Ctx) error {
|
|
currency := c.Query("currency", "ETB") // fallback default
|
|
|
|
games, err := h.virtualGameSvc.ListGames(c.Context(), currency)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusBadGateway, "failed to fetch games")
|
|
}
|
|
return c.JSON(games)
|
|
}
|
|
|
|
// RecommendGames godoc
|
|
// @Summary Recommend virtual games
|
|
// @Description Recommends games based on user history or randomly
|
|
// @Tags Virtual Games - PopOK
|
|
// @Produce json
|
|
// @Param user_id query int true "User ID"
|
|
// @Success 200 {array} domain.GameRecommendation
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /popok/games/recommend [get]
|
|
func (h *Handler) RecommendGames(c *fiber.Ctx) error {
|
|
userIDVal := c.Locals("user_id")
|
|
userID, ok := userIDVal.(int64)
|
|
if !ok || userID == 0 {
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid user ID")
|
|
}
|
|
|
|
recommendations, err := h.virtualGameSvc.RecommendGames(c.Context(), userID)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to recommend games")
|
|
}
|
|
|
|
return c.JSON(recommendations)
|
|
}
|
|
|
|
func (h *Handler) HandleTournamentWin(c *fiber.Ctx) error {
|
|
var req domain.PopOKWinRequest
|
|
|
|
if err := c.BodyParser(&req); err != nil {
|
|
h.logger.Error("Invalid tournament win request body", "error", err)
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Invalid request body",
|
|
})
|
|
}
|
|
|
|
resp, err := h.virtualGameSvc.ProcessTournamentWin(c.Context(), &req)
|
|
if err != nil {
|
|
h.logger.Error("Failed to process tournament win", "error", err)
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
func (h *Handler) HandlePromoWin(c *fiber.Ctx) error {
|
|
var req domain.PopOKWinRequest
|
|
|
|
if err := c.BodyParser(&req); err != nil {
|
|
h.logger.Error("Invalid promo win request body", "error", err)
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Invalid request body",
|
|
})
|
|
}
|
|
|
|
resp, err := h.virtualGameSvc.ProcessPromoWin(c.Context(), &req)
|
|
if err != nil {
|
|
h.logger.Error("Failed to process promo win", "error", err)
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
// AddFavoriteGame godoc
|
|
// @Summary Add game to favorites
|
|
// @Description Adds a game to the user's favorite games list
|
|
// @Tags VirtualGames - Favourites
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param body body domain.FavoriteGameRequest true "Game ID to add"
|
|
// @Success 201 {string} domain.Response "created"
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/virtual-game/favorites [post]
|
|
func (h *Handler) AddFavorite(c *fiber.Ctx) error {
|
|
userID := c.Locals("user_id").(int64)
|
|
|
|
var req domain.FavoriteGameRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
|
}
|
|
|
|
err := h.virtualGameSvc.AddFavoriteGame(c.Context(), userID, req.GameID)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Could not add favorite",
|
|
Error: err.Error(),
|
|
})
|
|
// return fiber.NewError(fiber.StatusInternalServerError, "Could not add favorite")
|
|
}
|
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
|
Message: "Game added to favorites",
|
|
StatusCode: fiber.StatusCreated,
|
|
Success: true,
|
|
})
|
|
// return c.SendStatus(fiber.StatusCreated)
|
|
}
|
|
|
|
// RemoveFavoriteGame godoc
|
|
// @Summary Remove game from favorites
|
|
// @Description Removes a game from the user's favorites
|
|
// @Tags VirtualGames - Favourites
|
|
// @Produce json
|
|
// @Param gameID path int64 true "Game ID to remove"
|
|
// @Success 200 {string} domain.Response "removed"
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/virtual-game/favorites/{gameID} [delete]
|
|
func (h *Handler) RemoveFavorite(c *fiber.Ctx) error {
|
|
userID := c.Locals("user_id").(int64)
|
|
gameID, _ := strconv.ParseInt(c.Params("gameID"), 10, 64)
|
|
|
|
err := h.virtualGameSvc.RemoveFavoriteGame(c.Context(), userID, gameID)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "Could not remove favorite")
|
|
}
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
// ListFavoriteGames godoc
|
|
// @Summary Get user's favorite games
|
|
// @Description Lists the games that the user marked as favorite
|
|
// @Tags VirtualGames - Favourites
|
|
// @Produce json
|
|
// @Success 200 {array} domain.GameRecommendation
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/virtual-game/favorites [get]
|
|
func (h *Handler) ListFavorites(c *fiber.Ctx) error {
|
|
userID := c.Locals("user_id").(int64)
|
|
|
|
games, err := h.virtualGameSvc.ListFavoriteGames(c.Context(), userID)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "Could not fetch favorites")
|
|
}
|
|
return c.Status(fiber.StatusOK).JSON(games)
|
|
}
|