package v1 import ( "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/gochat/gochat/internal/service" applogger "github.com/gochat/gochat/pkg/logger" "github.com/gochat/gochat/pkg/response" ) // LiveReportHandler handles live/real-time reporting endpoints. // Reference: Chatwoot app/controllers/api/v2/accounts/live_reports_controller.rb type LiveReportHandler struct { svc *service.AnalyticsService } func NewLiveReportHandler(svc *service.AnalyticsService) *LiveReportHandler { return &LiveReportHandler{svc: svc} } // ConversationMetrics returns real-time conversation counts (open, unattended, unassigned, pending). // GET /api/v1/accounts/:account_id/live_reports/conversation_metrics // Reference: Chatwoot live_reports#conversation_metrics — { open, unattended, unassigned, pending } func (h *LiveReportHandler) ConversationMetrics(c *gin.Context) { accountID := getAccountID(c) if accountID == 0 { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } teamID, ok := parseLiveReportTeamID(c) if !ok { return } result, err := h.svc.GetConversationMetricsForTeam(c.Request.Context(), accountID, teamID) if err != nil { applogger.L().Errorf("Live conversation metrics: %v", err) response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to get conversation metrics") return } c.JSON(http.StatusOK, result) } // GroupedConversationMetrics returns conversation metrics grouped by team_id or assignee_id. // GET /api/v1/accounts/:account_id/live_reports/grouped_conversation_metrics // Reference: Chatwoot live_reports#grouped_conversation_metrics — group_by=team_id|assignee_id // Returns array of { group_by_field, open, unattended, unassigned } func (h *LiveReportHandler) GroupedConversationMetrics(c *gin.Context) { accountID := getAccountID(c) if accountID == 0 { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } groupBy := c.Query("group_by") if groupBy != "team_id" && groupBy != "assignee_id" { // Reference: Chatwoot returns 422 with a raw { error } body for invalid group_by. c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{"error": "invalid group_by"}) return } teamID, ok := parseLiveReportTeamID(c) if !ok { return } result, err := h.svc.GetGroupedConversationMetricsForTeam(c.Request.Context(), accountID, groupBy, teamID) if err != nil { applogger.L().Errorf("Grouped conversation metrics: %v", err) response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to get grouped conversation metrics") return } c.JSON(http.StatusOK, result) } func parseLiveReportTeamID(c *gin.Context) (uint, bool) { teamIDStr := c.Query("team_id") if teamIDStr == "" { return 0, true } parsed, err := strconv.ParseUint(teamIDStr, 10, 64) if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team_id") return 0, false } return uint(parsed), true }