package handlers import ( "fmt" "strconv" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" "go.uber.org/zap" ) // GetAllOdds // @Summary Retrieve all odds // @Description Retrieve all odds from the database // @Tags prematch // @Accept json // @Produce json // @Success 200 {array} domain.OddMarketFilter // @Failure 500 {object} response.APIResponse // @Router /api/v1/odds [get] func (h *Handler) GetAllOdds(c *fiber.Ctx) error { limit, err := strconv.Atoi(c.Query("limit", "10")) // Default limit is 10 if err != nil || limit <= 0 { h.BadRequestLogger().Info("Invalid limit value", zap.Error(err)) return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") } offset, err := strconv.Atoi(c.Query("offset", "0")) // Default offset is 0 if err != nil || offset < 0 { h.BadRequestLogger().Info("Invalid offset value", zap.Error(err)) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } odds, err := h.prematchSvc.GetAllOdds(c.Context(), domain.OddMarketFilter{ Limit: domain.ValidInt32{ Value: int32(limit), Valid: true, }, Offset: domain.ValidInt32{ Value: int32(offset), Valid: true, }, }) if err != nil { h.InternalServerErrorLogger().Error("Failed to retrieve all odds", zap.Int("limit", limit), zap.Int("offset", offset), zap.Error(err), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "All odds retrieved successfully", odds, nil) } // GetAllOdds // @Summary Retrieve all odds // @Description Retrieve all odds from the database // @Tags prematch // @Accept json // @Produce json // @Success 200 {array} domain.OddMarketFilter // @Failure 500 {object} response.APIResponse // @Router /api/v1/{tenant_slug}/odds [get] func (h *Handler) GetAllTenantOdds(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } limit, err := strconv.Atoi(c.Query("limit", "10")) // Default limit is 10 if err != nil || limit <= 0 { h.BadRequestLogger().Info("Invalid limit value", zap.Error(err)) return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") } offset, err := strconv.Atoi(c.Query("offset", "0")) // Default offset is 0 if err != nil || offset < 0 { h.BadRequestLogger().Info("Invalid offset value", zap.Error(err)) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } odds, err := h.prematchSvc.GetAllOddsWithSettings(c.Context(), companyID.Value, domain.OddMarketFilter{ Limit: domain.ValidInt32{ Value: int32(limit), Valid: true, }, Offset: domain.ValidInt32{ Value: int32(offset), Valid: true, }, }) if err != nil { h.InternalServerErrorLogger().Error("Failed to retrieve all odds", zap.Int("limit", limit), zap.Int("offset", offset), zap.Error(err), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "All odds retrieved successfully", odds, nil) } // GetOddsByMarketID // @Summary Retrieve raw odds by Market ID // @Description Retrieve raw odds records using a Market ID // @Tags prematch // @Accept json // @Produce json // @Param upcoming_id path string true "Upcoming ID" // @Param market_id path string true "Market ID" // @Success 200 {array} domain.RawOddsByMarketID // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/odds/upcoming/{upcoming_id}/market/{market_id} [get] func (h *Handler) GetOddsByMarketID(c *fiber.Ctx) error { logFields := []zap.Field{ zap.String("market_id", c.Params("market_id")), zap.String("upcoming_id", c.Params("upcoming_id")), } marketIDStr := c.Params("market_id") marketID, err := strconv.ParseInt(marketIDStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Missing market_id", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Missing market_id") } eventIDStr := c.Params("upcoming_id") eventID, err := strconv.ParseInt(eventIDStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Missing upcoming_id", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Missing upcoming_id") } rawOdds, err := h.prematchSvc.GetOddsByMarketID(c.Context(), marketID, eventID) if err != nil { // Lets turn this into a warn because this is constantly going off // h.InternalServerErrorLogger().Warn("Failed to get raw odds by market ID", append(logFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Raw odds retrieved successfully", rawOdds, nil) } // GetTenantOddsByMarketID // @Summary Retrieve raw odds by Market ID // @Description Retrieve raw odds records using a Market ID // @Tags prematch // @Accept json // @Produce json // @Param upcoming_id path string true "Upcoming ID" // @Param market_id path string true "Market ID" // @Success 200 {array} domain.RawOddsByMarketID // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/{tenant_slug}/odds/upcoming/{upcoming_id}/market/{market_id} [get] func (h *Handler) GetTenantOddsByMarketID(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } logFields := []zap.Field{ zap.String("market_id", c.Params("market_id")), zap.String("upcoming_id", c.Params("upcoming_id")), zap.Int64("company_id", companyID.Value), } marketIDStr := c.Params("market_id") marketID, err := strconv.ParseInt(marketIDStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Missing market_id", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Missing market_id") } eventIDStr := c.Params("upcoming_id") eventID, err := strconv.ParseInt(eventIDStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Missing upcoming_id", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Missing upcoming_id") } oddMarket, err := h.prematchSvc.GetOddsWithSettingsByMarketID(c.Context(), marketID, eventID, companyID.Value) if err != nil { // Lets turn this into a warn because this is constantly going off // h.InternalServerErrorLogger().Warn("Failed to get raw odds by market ID", append(logFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Raw odds retrieved successfully", oddMarket, nil) } // GetOddsByUpcomingID // @Summary Retrieve prematch odds by upcoming ID (FI) // @Description Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination // @Tags prematch // @Accept json // @Produce json // @Param upcoming_id path string true "Upcoming Event ID (FI)" // @Param limit query int false "Number of results to return (default: 10)" // @Param offset query int false "Number of results to skip (default: 0)" // @Success 200 {array} domain.OddMarketWithEventFilter // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/odds/upcoming/{upcoming_id} [get] func (h *Handler) GetOddsByUpcomingID(c *fiber.Ctx) error { logFields := []zap.Field{ zap.String("upcoming_id", c.Params("upcoming_id")), zap.String("limit_param", c.Query("limit", "10")), zap.String("offset_param", c.Query("offset", "0")), } eventIDStr := c.Params("upcoming_id") eventID, err := strconv.ParseInt(eventIDStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Missing upcoming_id", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Missing upcoming_id") } limit, err := strconv.Atoi(c.Query("limit", "10")) // Default limit is 10 if err != nil || limit <= 0 { logFields = append(logFields, zap.Error(err)) h.BadRequestLogger().Info("Invalid limit value", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") } offset, err := strconv.Atoi(c.Query("offset", "0")) // Default offset is 0 if err != nil || offset < 0 { logFields = append(logFields, zap.Error(err)) h.BadRequestLogger().Info("Invalid offset value", logFields...) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } odds, err := h.prematchSvc.GetOddsByEventID(c.Context(), eventID, domain.OddMarketWithEventFilter{}) if err != nil { logFields = append(logFields, zap.Error(err)) h.InternalServerErrorLogger().Error("Failed to retrieve odds", append(logFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve odds"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Odds retrieved successfully", odds, nil) } // GetTenantOddsByUpcomingID // @Summary Retrieve prematch odds by upcoming ID (FI) // @Description Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination // @Tags prematch // @Accept json // @Produce json // @Param upcoming_id path string true "Upcoming Event ID (FI)" // @Param limit query int false "Number of results to return (default: 10)" // @Param offset query int false "Number of results to skip (default: 0)" // @Success 200 {array} domain.OddMarketFilter // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/{tenant_slug}/odds/upcoming/{upcoming_id} [get] func (h *Handler) GetTenantOddsByUpcomingID(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } logFields := []zap.Field{ zap.String("upcoming_id", c.Params("upcoming_id")), zap.String("limit_param", c.Query("limit", "10")), zap.String("offset_param", c.Query("offset", "0")), zap.Int64("company_id", companyID.Value), } eventIDStr := c.Params("upcoming_id") eventID, err := strconv.ParseInt(eventIDStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Missing upcoming_id", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Missing upcoming_id") } limit, err := strconv.Atoi(c.Query("limit", "10")) // Default limit is 10 if err != nil || limit <= 0 { logFields = append(logFields, zap.Error(err)) h.BadRequestLogger().Info("Invalid limit value", logFields...) return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") } offset, err := strconv.Atoi(c.Query("offset", "0")) // Default offset is 0 if err != nil || offset < 0 { logFields = append(logFields, zap.Error(err)) h.BadRequestLogger().Info("Invalid offset value", logFields...) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } odds, err := h.prematchSvc.GetOddsWithSettingsByEventID(c.Context(), eventID, companyID.Value, domain.OddMarketFilter{}) if err != nil { logFields = append(logFields, zap.Error(err)) h.InternalServerErrorLogger().Error("Failed to retrieve odds", append(logFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve odds"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Odds retrieved successfully", odds, nil) } func (h *Handler) SaveTenantOddsSetting(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } var req domain.CreateOddMarketSettingsReq if err := c.BodyParser(&req); err != nil { h.BadRequestLogger().Info("Failed to parse CreateOddMarketSettingsReq", zap.Int64("CompanyID", companyID.Value), zap.Error(err), ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } logFields := []zap.Field{ zap.Int64("companyID", companyID.Value), zap.Any("is_active", req.IsActive), zap.Any("custom_odd", req.CustomOdd), } valErrs, ok := h.validator.Validate(c, req) if !ok { var errMsg string for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } h.BadRequestLogger().Error("Failed to validate insert odd settings", append(logFields, zap.String("errMsg", errMsg))..., ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } err := h.prematchSvc.SaveOddsSettingReq(c.Context(), companyID.Value, req) if err != nil { logFields = append(logFields, zap.Error(err)) h.InternalServerErrorLogger().Error("Failed to save odds settings", append(logFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, "Failed to save odds settings"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Odds Settings saved successfully", nil, nil) } func (h *Handler) SaveOddSettings(c *fiber.Ctx) error { var req domain.UpdateGlobalOddMarketSettingsReq if err := c.BodyParser(&req); err != nil { h.BadRequestLogger().Info("Failed to parse CreateOddMarketSettingsReq", zap.Error(err), ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } logFields := []zap.Field{ zap.Any("is_active", req.IsActive), } valErrs, ok := h.validator.Validate(c, req) if !ok { var errMsg string for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } h.BadRequestLogger().Error("Failed to validate insert odd settings", append(logFields, zap.String("errMsg", errMsg))..., ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } err := h.prematchSvc.UpdateGlobalOddsSetting(c.Context(), domain.UpdateGlobalOddMarketSettings{ OddMarketID: req.OddMarketID, IsActive: domain.ConvertBoolPtr(req.IsActive), }) if err != nil { logFields = append(logFields, zap.Error(err)) h.InternalServerErrorLogger().Error("Failed to save odds settings", append(logFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, "Failed to save odds settings"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Odds Settings saved successfully", nil, nil) } func (h *Handler) RemoveOddsSettings(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } idStr := c.Params("id") oddID, err := strconv.ParseInt(idStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Failed to parse odd id", zap.String("id", idStr)) return fiber.NewError(fiber.StatusBadRequest, "Missing id") } err = h.prematchSvc.DeleteCompanyOddsSettingByOddMarketID(c.Context(), companyID.Value, oddID) if err != nil { h.InternalServerErrorLogger().Error("Failed to retrieve odds", zap.Error(err)) return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove odds settings"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Odds settings successfully removed ", nil, nil) } func (h *Handler) RemoveAllOddsSettings(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } err := h.prematchSvc.DeleteAllCompanyOddsSetting(c.Context(), companyID.Value) if err != nil { h.InternalServerErrorLogger().Error("Failed to remove all odd settings", zap.Int64("company_id", companyID.Value), zap.Error(err)) return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove all odds settings"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Odds settings successfully removed ", nil, nil) } type UpdateAllBetStatusByOddIDReq struct { Status domain.OutcomeStatus `json:"status"` } func (h *Handler) UpdateAllBetOutcomeStatusByOddID(c *fiber.Ctx) error { idStr := c.Params("id") oddID, err := strconv.ParseInt(idStr, 10, 64) if err != nil { h.BadRequestLogger().Info("Failed to parse odd_id", zap.String("id", idStr)) return fiber.NewError(fiber.StatusBadRequest, "Missing id") } var req UpdateAllBetStatusByOddIDReq if err := c.BodyParser(&req); err != nil { h.BadRequestLogger().Info("Failed to parse event id", zap.Error(err), ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } logFields := []zap.Field{ zap.Any("status", req.Status), } valErrs, ok := h.validator.Validate(c, req) if !ok { var errMsg string for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } h.BadRequestLogger().Error("Failed to insert odd settings", append(logFields, zap.String("errMsg", errMsg))..., ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } _, err = h.betSvc.UpdateBetOutcomeStatusForOddId(c.Context(), oddID, req.Status) if err != nil { h.InternalServerErrorLogger().Error("Failed to update bet status by odd id", zap.Int64("oddID", oddID), zap.Error(err), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Updated All Bet Outcome Status Successfully", nil, nil) }