package handlers import ( "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} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @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") } 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} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @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 response.WriteJSON(c, fiber.StatusOK, "Player info retrieved", resp, nil) } 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) }