package handlers import ( "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/gofiber/fiber/v2" "go.uber.org/zap" ) // CreateIssue godoc // @Summary Report an issue // @Description Allows a customer to report a new issue related to the betting platform // @Tags Issues // @Accept json // @Produce json // @Param issue body domain.ReportedIssue true "Issue to report" // @Success 201 {object} domain.ReportedIssue // @Failure 400 {object} domain.ErrorResponse // @Failure 500 {object} domain.ErrorResponse // @Router /api/v1/issues [post] func (h *Handler) CreateIssue(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) userID := c.Locals("user_id").(int64) var req domain.ReportedIssueReq if err := c.BodyParser(&req); err != nil { h.mongoLoggerSvc.Info("Invalid request body", zap.Int64("userID", userID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } created, err := h.issueReportingSvc.CreateReportedIssue(c.Context(), req, userID, role) if err != nil { h.mongoLoggerSvc.Error("Failed to report issue", zap.String("role", string(role)), zap.Int64("userID", userID), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "failed to report issue:"+err.Error()) } return c.Status(fiber.StatusCreated).JSON(created) } // GetUserIssues godoc // @Summary Get reported issues by a user // @Description Returns all issues reported by a specific user // @Tags Issues // @Produce json // @Param user_id path int true "User ID" // @Param limit query int false "Limit" // @Param offset query int false "Offset" // @Success 200 {array} domain.ReportedIssue // @Failure 400 {object} domain.ErrorResponse // @Failure 500 {object} domain.ErrorResponse // @Router /api/v1/issues/user/{user_id} [get] func (h *Handler) GetUserIssues(c *fiber.Ctx) error { userID, err := strconv.ParseInt(c.Params("user_id"), 10, 64) if err != nil { h.mongoLoggerSvc.Info("Failed to parse user id", zap.Int64("userID", userID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID") } limit, offset := getPaginationParams(c) issues, err := h.issueReportingSvc.GetIssuesForUser(c.Context(), userID, limit, offset) if err != nil { h.mongoLoggerSvc.Error("Failed to get user issue", zap.Int64("userID", userID), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to get user issue"+err.Error()) } return c.JSON(issues) } // GetAllIssues godoc // @Summary Get all reported issues // @Description Admin endpoint to list all reported issues with pagination // @Tags Issues // @Produce json // @Param limit query int false "Limit" // @Param offset query int false "Offset" // @Success 200 {array} domain.ReportedIssue // @Failure 500 {object} domain.ErrorResponse // @Router /api/v1/issues [get] func (h *Handler) GetAllIssues(c *fiber.Ctx) error { limit, offset := getPaginationParams(c) issues, err := h.issueReportingSvc.GetAllIssues(c.Context(), limit, offset) if err != nil { h.mongoLoggerSvc.Error("Failed to get all issues", zap.Int("limit", limit), zap.Int("offset", offset), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to get all issues:"+err.Error()) } return c.JSON(issues) } // UpdateIssueStatus godoc // @Summary Update issue status // @Description Admin endpoint to update the status of a reported issue // @Tags Issues // @Accept json // @Param issue_id path int true "Issue ID" // @Param status body object{status=string} true "New issue status (pending, in_progress, resolved, rejected)" // @Success 204 // @Failure 400 {object} domain.ErrorResponse // @Router /api/v1/issues/{issue_id}/status [patch] func (h *Handler) UpdateIssueStatus(c *fiber.Ctx) error { issueID, err := strconv.ParseInt(c.Params("issue_id"), 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid issue ID") } var body struct { Status string `json:"status"` } if err := c.BodyParser(&body); err != nil || body.Status == "" { h.mongoLoggerSvc.Info("Invalid status payload", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid status payload"+err.Error()) } if err := h.issueReportingSvc.UpdateIssueStatus(c.Context(), issueID, body.Status); err != nil { h.mongoLoggerSvc.Error("Failed to update issue status", zap.Int64("issueID", issueID), zap.String("status", body.Status), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } return c.SendStatus(fiber.StatusNoContent) } // DeleteIssue godoc // @Summary Delete a reported issue // @Description Admin endpoint to delete a reported issue // @Tags Issues // @Param issue_id path int true "Issue ID" // @Success 204 // @Failure 400 {object} domain.ErrorResponse // @Failure 500 {object} domain.ErrorResponse // @Router /api/v1/issues/{issue_id} [delete] func (h *Handler) DeleteIssue(c *fiber.Ctx) error { issueID, err := strconv.ParseInt(c.Params("issue_id"), 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid issue ID") } if err := h.issueReportingSvc.DeleteIssue(c.Context(), issueID); err != nil { h.mongoLoggerSvc.Error("Failed to delete issue", zap.Int64("issueID", issueID), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return c.SendStatus(fiber.StatusNoContent) } func getPaginationParams(c *fiber.Ctx) (limit, offset int) { limit = 20 offset = 0 if l, err := strconv.Atoi(c.Query("limit")); err == nil && l > 0 { limit = l } if o, err := strconv.Atoi(c.Query("offset")); err == nil && o >= 0 { offset = o } return }