package handlers import ( "context" "encoding/json" "errors" "fmt" "log" "strings" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/gofiber/fiber/v2" ) // GetAtlasVGames godoc // @Summary List Atlas virtual games // @Description Retrieves available Atlas virtual games from the provider // @Tags Virtual Games - Atlas // @Produce json // @Success 200 {object} domain.Response{data=[]domain.AtlasGameEntity} // @Failure 502 {object} domain.ErrorResponse // @Router /api/v1/atlas/games [get] func (h *Handler) GetAtlasVGames(c *fiber.Ctx) error { // Call the service games, err := h.veliVirtualGameSvc.GetAtlasVGames(c.Context()) if err != nil { log.Println("GetAtlasVGames error:", err) return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ Message: "Failed to fetch Atlas virtual games", Error: err.Error(), }) } // Return the list of games return c.Status(fiber.StatusOK).JSON(domain.Response{ Message: "Atlas virtual games retrieved successfully", Data: games, StatusCode: fiber.StatusOK, Success: true, }) } // InitAtlasGame godoc // @Summary Start an Atlas virtual game session // @Description Initializes a game session for the given player using Atlas virtual game provider // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.AtlasGameInitRequest true "Start game input" // @Success 200 {object} domain.Response{data=domain.AtlasGameInitResponse} // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /api/v1/atlas/init-game [post] func (h *Handler) InitAtlasGame(c *fiber.Ctx) error { // Retrieve user ID from context userId, ok := c.Locals("user_id").(int64) if !ok { return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{ Error: "missing user id", Message: "Unauthorized", }) } var req domain.AtlasGameInitRequest if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid request body", Error: err.Error(), }) } // Attach user ID to request req.PlayerID = fmt.Sprintf("%d", userId) // Default language if not provided if req.Language == "" { req.Language = "en" } // Default currency if not provided if req.Currency == "" { req.Currency = "USD" } // Call the service res, err := h.atlasVirtualGameSvc.InitGame(context.Background(), req) if err != nil { log.Println("InitAtlasGame error:", err) return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ Message: "Failed to initialize Atlas game", Error: err.Error(), }) } return c.Status(fiber.StatusOK).JSON(domain.Response{ Message: "Game initialized successfully", Data: res, StatusCode: fiber.StatusOK, Success: true, }) } // AtlasGetUserDataCallback godoc // @Summary Atlas Get User Data callback // @Description Callback endpoint for Atlas game server to fetch player balance // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.AtlasGetUserDataRequest true "Get user data input" // @Success 200 {object} domain.AtlasGetUserDataResponse // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /account [post] func (h *Handler) AtlasGetUserDataCallback(c *fiber.Ctx) error { var req domain.AtlasGetUserDataRequest if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid request body", Error: err.Error(), }) } // Optional: validate casino_id matches your configured Atlas casino if req.CasinoID != h.Cfg.Atlas.CasinoID { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid casino_id", Error: "unauthorized request", }) } // Call service to get player data res, err := h.atlasVirtualGameSvc.GetUserData(c.Context(), req) if err != nil { log.Println("AtlasGetUserDataCallback error:", err) return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ Message: "Failed to fetch user data", Error: err.Error(), }) } // Return Atlas expected response return c.JSON(res) } // HandleAtlasBetWin godoc // @Summary Atlas BetWin callback // @Description Processes a Bet and Win request from Atlas provider // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.AtlasBetWinRequest true "Atlas BetWin input" // @Success 200 {object} domain.AtlasBetWinResponse // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /betwin [post] func (h *Handler) HandleAtlasBetWin(c *fiber.Ctx) error { body := c.Body() if len(body) == 0 { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Empty request body", Error: "Request body cannot be empty", }) } var req domain.AtlasBetWinRequest if err := json.Unmarshal(body, &req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid Atlas BetWin request", Error: err.Error(), }) } res, err := h.atlasVirtualGameSvc.ProcessBetWin(c.Context(), req) if err != nil { // Handle known errors specifically code := fiber.StatusInternalServerError errMsg := err.Error() switch { case errors.Is(err, domain.ErrInsufficientBalance): code = fiber.StatusBadRequest errMsg = "INSUFFICIENT_BALANCE" case strings.Contains(err.Error(), "invalid casino_id"): code = fiber.StatusBadRequest case strings.Contains(err.Error(), "invalid playerID"): code = fiber.StatusBadRequest } return c.Status(code).JSON(domain.ErrorResponse{ Message: "Failed to process Atlas BetWin", Error: errMsg, }) } return c.Status(fiber.StatusOK).JSON(res) } // HandleRoundResult godoc // @Summary Atlas Round Result callback // @Description Processes a round result from Atlas or other providers // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.RoundResultRequest true "Round result input" // @Success 200 {object} domain.RoundResultResponse // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /result [post] func (h *Handler) HandleRoundResult(c *fiber.Ctx) error { body := c.Body() if len(body) == 0 { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Empty request body", Error: "Request body cannot be empty", }) } var req domain.RoundResultRequest if err := json.Unmarshal(body, &req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid RoundResult request", Error: err.Error(), }) } res, err := h.atlasVirtualGameSvc.ProcessRoundResult(c.Context(), req) if err != nil { code := fiber.StatusInternalServerError errMsg := err.Error() // Validation errors if strings.Contains(err.Error(), "missing player_id") || strings.Contains(err.Error(), "missing transaction_id") { code = fiber.StatusBadRequest } return c.Status(code).JSON(domain.ErrorResponse{ Message: "Failed to process round result", Error: errMsg, }) } return c.Status(fiber.StatusOK).JSON(res) } // HandleRollback godoc // @Summary Atlas Rollback callback // @Description Processes a rollback request from Atlas or other providers // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.RollbackRequest true "Rollback request input" // @Success 200 {object} domain.RollbackResponse // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /rollback [post] func (h *Handler) HandleRollback(c *fiber.Ctx) error { body := c.Body() if len(body) == 0 { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Empty request body", Error: "Request body cannot be empty", }) } var req domain.RollbackRequest if err := json.Unmarshal(body, &req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid Rollback request", Error: err.Error(), }) } res, err := h.atlasVirtualGameSvc.ProcessRollBack(c.Context(), req) if err != nil { code := fiber.StatusInternalServerError errMsg := err.Error() // Validation errors if strings.Contains(err.Error(), "missing player_id") || strings.Contains(err.Error(), "missing transaction_id") { code = fiber.StatusBadRequest } return c.Status(code).JSON(domain.ErrorResponse{ Message: "Failed to process rollback", Error: errMsg, }) } return c.Status(fiber.StatusOK).JSON(res) } // CreateFreeSpin godoc // @Summary Create free spins for a player // @Description Sends a request to Atlas to create free spins/bets for a given player // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.FreeSpinRequest true "Free spin input" // @Success 200 {object} domain.Response{data=domain.FreeSpinResponse} // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /api/v1/atlas/freespin [post] func (h *Handler) CreateFreeSpin(c *fiber.Ctx) error { // Get the authenticated user ID userId, ok := c.Locals("user_id").(int64) if !ok { return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{ Error: "missing user id", Message: "Unauthorized", }) } var req domain.FreeSpinRequest if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid request body", Error: err.Error(), }) } // Attach player ID from authenticated user req.PlayerID = fmt.Sprintf("%d", userId) res, err := h.atlasVirtualGameSvc.CreateFreeSpin(c.Context(), req) if err != nil { log.Println("CreateFreeSpin error:", err) return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ Message: "Failed to create free spins", Error: err.Error(), }) } return c.Status(fiber.StatusOK).JSON(domain.Response{ Message: "Free spins created successfully", Data: res, StatusCode: fiber.StatusOK, Success: true, }) } // FreeSpinResultCallback godoc // @Summary Free Spin/Bet result callback // @Description Handles the result of a free spin/bet from the game server // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.FreeSpinResultRequest true "Free spin result input" // @Success 200 {object} domain.FreeSpinResultResponse // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /freespin [post] func (h *Handler) FreeSpinResultCallback(c *fiber.Ctx) error { // Read raw request body body := c.Body() if len(body) == 0 { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Empty request body", Error: "Request body cannot be empty", }) } // Unmarshal into FreeSpinResultRequest var req domain.FreeSpinResultRequest if err := json.Unmarshal(body, &req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid free spin result request", Error: err.Error(), }) } // Process the free spin result res, err := h.atlasVirtualGameSvc.ProcessFreeSpinResult(c.Context(), req) if err != nil { log.Println("FreeSpinResultCallback error:", err) return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ Message: "Failed to process free spin result", Error: err.Error(), }) } return c.Status(fiber.StatusOK).JSON(res) } // JackpotCallback godoc // @Summary Jackpot result callback // @Description Handles the jackpot result from the game server // @Tags Virtual Games - Atlas // @Accept json // @Produce json // @Param request body domain.JackpotRequest true "Jackpot result input" // @Success 200 {object} domain.JackpotResponse // @Failure 400 {object} domain.ErrorResponse // @Failure 502 {object} domain.ErrorResponse // @Router /jackpot [post] func (h *Handler) JackpotCallback(c *fiber.Ctx) error { // Read raw request body body := c.Body() if len(body) == 0 { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Empty request body", Error: "Request body cannot be empty", }) } // Unmarshal into JackpotRequest var req domain.JackpotRequest if err := json.Unmarshal(body, &req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid jackpot request", Error: err.Error(), }) } // Process the jackpot res, err := h.atlasVirtualGameSvc.ProcessJackPot(c.Context(), req) if err != nil { log.Println("JackpotCallback error:", err) return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ Message: "Failed to process jackpot", Error: err.Error(), }) } return c.Status(fiber.StatusOK).JSON(res) }