Yimaru-BackEnd/internal/web_server/handlers/bet_handler.go
2025-04-12 03:27:50 +03:00

250 lines
8.4 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 BetRes struct {
ID int64 `json:"id" example:"1"`
Outcomes []domain.Outcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
Status domain.BetStatus `json:"status" example:"1"`
FullName string `json:"full_name" example:"John"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
BranchID int64 `json:"branch_id" example:"2"`
UserID int64 `json:"user_id" example:"2"`
IsShopBet bool `json:"is_shop_bet" example:"false"`
}
// CreateBet godoc
// @Summary Create a bet
// @Description Creates a bet
// @Tags bet
// @Accept json
// @Produce json
// @Param createBet body CreateBetReq true "Creates bet"
// @Success 200 {object} BetRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /bet [post]
func (h *Handler) CreateBet(c *fiber.Ctx) error {
type CreateBetReq struct {
Outcomes []int64 `json:"outcomes" validate:"required" example:"[1, 2, 3]"`
Amount float32 `json:"amount" validate:"required" example:"100.0"`
TotalOdds float32 `json:"total_odds" validate:"required" example:"4.22"`
Status domain.BetStatus `json:"status" validate:"required" example:"1"`
FullName string `json:"full_name" example:"John"`
PhoneNumber string `json:"phone_number" validate:"required" example:"1234567890"`
IsShopBet bool `json:"is_shop_bet" example:"false"`
}
var req CreateBetReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("Failed to parse CreateBet 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)
}
// TODO: Check the token, find the role, and get the branch ID from there
isShopBet := true
branchID := int64(1)
var userID int64
// TODO: Validate Outcomes Here and make sure they didn't expire
bet, err := h.betSvc.CreateBet(c.Context(), domain.CreateBet{
Outcomes: req.Outcomes,
Amount: domain.Currency(req.Amount),
TotalOdds: req.TotalOdds,
Status: req.Status,
FullName: req.FullName,
PhoneNumber: req.PhoneNumber,
BranchID: domain.ValidInt64{
Value: branchID,
Valid: isShopBet,
},
UserID: domain.ValidInt64{
Value: userID,
Valid: !isShopBet,
},
IsShopBet: req.IsShopBet,
})
if err != nil {
h.logger.Error("Failed to create bet", "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create bet")
}
// TODO: Reduce amount from the branch wallet (assuming walletSvc integration)
// This would typically be done here or in the bet service
if !req.IsShopBet && req.PhoneNumber != "" {
if err := h.referralSvc.ProcessBetReferral(c.Context(), req.PhoneNumber, float64(req.Amount)); err != nil {
h.logger.Warn("Failed to process bet referral", "phone", req.PhoneNumber, "amount", req.Amount, "error", err)
}
}
res := convertBet(bet)
return response.WriteJSON(c, fiber.StatusOK, "Bet created successfully", res, nil)
}
// GetAllBet godoc
// @Summary Gets all bets
// @Description Gets all the bets
// @Tags bet
// @Accept json
// @Produce json
// @Success 200 {array} BetRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /bet [get]
func (h *Handler) GetAllBet(c *fiber.Ctx) error {
bets, err := h.betSvc.GetAllBets(c.Context())
if err != nil {
h.logger.Error("Failed to get bets", "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets")
}
res := make([]BetRes, len(bets))
for i, bet := range bets {
res[i] = convertBet(bet)
}
return response.WriteJSON(c, fiber.StatusOK, "All bets retrieved successfully", res, nil)
}
// GetBetByID godoc
// @Summary Gets bet by id
// @Description Gets a single bet by id
// @Tags bet
// @Accept json
// @Produce json
// @Param id path int true "Bet ID"
// @Success 200 {object} BetRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /bet/{id} [get]
func (h *Handler) GetBetByID(c *fiber.Ctx) error {
type BetRes struct {
ID int64 `json:"id" example:"1"`
Outcomes []domain.Outcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
Status domain.BetStatus `json:"status" example:"1"`
FullName string `json:"full_name" example:"John"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
BranchID int64 `json:"branch_id" example:"2"`
UserID int64 `json:"user_id" example:"2"`
IsShopBet bool `json:"is_shop_bet" example:"false"`
}
betID := c.Params("id")
id, err := strconv.ParseInt(betID, 10, 64)
if err != nil {
h.logger.Error("Invalid bet ID", "betID", betID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid bet ID")
}
bet, err := h.betSvc.GetBetByID(c.Context(), id)
if err != nil {
h.logger.Error("Failed to get bet by ID", "betID", id, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bet")
}
res := convertBet(bet)
return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil)
}
// UpdateCashOut godoc
// @Summary Updates the cashed out field
// @Description Updates the cashed out field
// @Tags bet
// @Accept json
// @Produce json
// @Param id path int true "Bet ID"
// @Param updateCashOut body UpdateCashOutReq true "Updates Cashed Out"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /bet/{id} [patch]
func (h *Handler) UpdateCashOut(c *fiber.Ctx) error {
type UpdateCashOutReq struct {
CashedOut bool `json:"cashed_out" validate:"required" example:"true"`
}
betID := c.Params("id")
id, err := strconv.ParseInt(betID, 10, 64)
if err != nil {
h.logger.Error("Invalid bet ID", "betID", betID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid bet ID")
}
var req UpdateCashOutReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("Failed to parse UpdateCashOut 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)
}
err = h.betSvc.UpdateCashOut(c.Context(), id, req.CashedOut)
if err != nil {
h.logger.Error("Failed to update cash out bet", "betID", id, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update cash out bet")
}
return response.WriteJSON(c, fiber.StatusOK, "Bet updated successfully", nil, nil)
}
// DeleteBet godoc
// @Summary Deletes bet by id
// @Description Deletes bet by id
// @Tags bet
// @Accept json
// @Produce json
// @Param id path int true "Bet ID"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /bet/{id} [delete]
func (h *Handler) DeleteBet(c *fiber.Ctx) error {
betID := c.Params("id")
id, err := strconv.ParseInt(betID, 10, 64)
if err != nil {
h.logger.Error("Invalid bet ID", "betID", betID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid bet ID")
}
err = h.betSvc.DeleteBet(c.Context(), id)
if err != nil {
h.logger.Error("Failed to delete bet by ID", "betID", id, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete bet")
}
return response.WriteJSON(c, fiber.StatusOK, "Bet removed successfully", nil, nil)
}
func convertBet(bet domain.Bet) BetRes {
return BetRes{
ID: bet.ID,
Outcomes: bet.Outcomes,
Amount: bet.Amount.Float64(),
TotalOdds: bet.TotalOdds,
Status: bet.Status,
FullName: bet.FullName,
PhoneNumber: bet.PhoneNumber,
BranchID: bet.BranchID.Value,
UserID: bet.UserID.Value,
IsShopBet: bet.IsShopBet,
}
}