package handlers import ( "errors" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/treytartt/casera-api/internal/middleware" "github.com/treytartt/casera-api/internal/models" "github.com/treytartt/casera-api/internal/services" ) // NotificationHandler handles notification-related HTTP requests type NotificationHandler struct { notificationService *services.NotificationService } // NewNotificationHandler creates a new notification handler func NewNotificationHandler(notificationService *services.NotificationService) *NotificationHandler { return &NotificationHandler{notificationService: notificationService} } // ListNotifications handles GET /api/notifications/ func (h *NotificationHandler) ListNotifications(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) limit := 50 offset := 0 if l := c.Query("limit"); l != "" { if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 { limit = parsed } } if o := c.Query("offset"); o != "" { if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 { offset = parsed } } notifications, err := h.notificationService.GetNotifications(user.ID, limit, offset) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "count": len(notifications), "results": notifications, }) } // GetUnreadCount handles GET /api/notifications/unread-count/ func (h *NotificationHandler) GetUnreadCount(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) count, err := h.notificationService.GetUnreadCount(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"unread_count": count}) } // MarkAsRead handles POST /api/notifications/:id/read/ func (h *NotificationHandler) MarkAsRead(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) notificationID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid notification ID"}) return } err = h.notificationService.MarkAsRead(uint(notificationID), user.ID) if err != nil { if errors.Is(err, services.ErrNotificationNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "Notification marked as read"}) } // MarkAllAsRead handles POST /api/notifications/mark-all-read/ func (h *NotificationHandler) MarkAllAsRead(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) err := h.notificationService.MarkAllAsRead(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "All notifications marked as read"}) } // GetPreferences handles GET /api/notifications/preferences/ func (h *NotificationHandler) GetPreferences(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) prefs, err := h.notificationService.GetPreferences(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, prefs) } // UpdatePreferences handles PUT/PATCH /api/notifications/preferences/ func (h *NotificationHandler) UpdatePreferences(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) var req services.UpdatePreferencesRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } prefs, err := h.notificationService.UpdatePreferences(user.ID, &req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, prefs) } // RegisterDevice handles POST /api/notifications/devices/ func (h *NotificationHandler) RegisterDevice(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) var req services.RegisterDeviceRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } device, err := h.notificationService.RegisterDevice(user.ID, &req) if err != nil { if errors.Is(err, services.ErrInvalidPlatform) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, device) } // ListDevices handles GET /api/notifications/devices/ func (h *NotificationHandler) ListDevices(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) devices, err := h.notificationService.ListDevices(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, devices) } // DeleteDevice handles DELETE /api/notifications/devices/:id/ func (h *NotificationHandler) DeleteDevice(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) deviceID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"}) return } platform := c.Query("platform") if platform == "" { platform = "ios" // Default to iOS } err = h.notificationService.DeleteDevice(uint(deviceID), platform, user.ID) if err != nil { if errors.Is(err, services.ErrInvalidPlatform) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "Device removed"}) }