package service import ( "context" "math" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/contract" "apskel-pos-be/internal/models" "apskel-pos-be/internal/processor" "apskel-pos-be/internal/transformer" "github.com/google/uuid" ) type NotificationService interface { Send(ctx context.Context, req *contract.SendNotificationRequest, createdBy uuid.UUID) *contract.Response Broadcast(ctx context.Context, req *contract.BroadcastNotificationRequest, organizationID, createdBy uuid.UUID) *contract.Response MarkAsRead(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response MarkAllAsRead(ctx context.Context, userID uuid.UUID) *contract.Response DeleteForUser(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response ListForUser(ctx context.Context, req *contract.ListNotificationsRequest, userID uuid.UUID) *contract.Response GetByID(ctx context.Context, id uuid.UUID) *contract.Response } type NotificationServiceImpl struct { notificationProcessor processor.NotificationProcessor } func NewNotificationService(notificationProcessor processor.NotificationProcessor) *NotificationServiceImpl { return &NotificationServiceImpl{ notificationProcessor: notificationProcessor, } } func (s *NotificationServiceImpl) Send(ctx context.Context, req *contract.SendNotificationRequest, createdBy uuid.UUID) *contract.Response { modelReq := &models.SendNotificationRequest{ Title: req.Title, Body: req.Body, Type: req.Type, Category: req.Category, Priority: req.Priority, ImageURL: req.ImageURL, ActionURL: req.ActionURL, NotifiableType: req.NotifiableType, NotifiableID: req.NotifiableID, Data: req.Data, ReceiverIDs: req.ReceiverIDs, ScheduledAt: req.ScheduledAt, ExpiredAt: req.ExpiredAt, CreatedBy: &createdBy, } resp, err := s.notificationProcessor.Send(ctx, modelReq) if err != nil { errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error()) return contract.BuildErrorResponse([]*contract.ResponseError{errResp}) } return contract.BuildSuccessResponse(transformer.NotificationModelResponseToContract(resp)) } func (s *NotificationServiceImpl) Broadcast(ctx context.Context, req *contract.BroadcastNotificationRequest, organizationID, createdBy uuid.UUID) *contract.Response { modelReq := &models.BroadcastNotificationRequest{ Title: req.Title, Body: req.Body, Type: req.Type, Category: req.Category, Priority: req.Priority, ImageURL: req.ImageURL, ActionURL: req.ActionURL, NotifiableType: req.NotifiableType, NotifiableID: req.NotifiableID, Data: req.Data, OrganizationID: organizationID, ScheduledAt: req.ScheduledAt, ExpiredAt: req.ExpiredAt, CreatedBy: &createdBy, } resp, err := s.notificationProcessor.Broadcast(ctx, modelReq) if err != nil { errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error()) return contract.BuildErrorResponse([]*contract.ResponseError{errResp}) } return contract.BuildSuccessResponse(transformer.NotificationModelResponseToContract(resp)) } func (s *NotificationServiceImpl) MarkAsRead(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response { resp, err := s.notificationProcessor.MarkAsRead(ctx, receiverID, userID) if err != nil { errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error()) return contract.BuildErrorResponse([]*contract.ResponseError{errResp}) } return contract.BuildSuccessResponse(transformer.NotificationReceiverModelResponseToContract(resp)) } func (s *NotificationServiceImpl) MarkAllAsRead(ctx context.Context, userID uuid.UUID) *contract.Response { if err := s.notificationProcessor.MarkAllAsRead(ctx, userID); err != nil { errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error()) return contract.BuildErrorResponse([]*contract.ResponseError{errResp}) } return contract.BuildSuccessResponse(map[string]interface{}{"message": "All notifications marked as read"}) } func (s *NotificationServiceImpl) DeleteForUser(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response { if err := s.notificationProcessor.DeleteForUser(ctx, receiverID, userID); err != nil { errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error()) return contract.BuildErrorResponse([]*contract.ResponseError{errResp}) } return contract.BuildSuccessResponse(map[string]interface{}{"message": "Notification deleted"}) } func (s *NotificationServiceImpl) ListForUser(ctx context.Context, req *contract.ListNotificationsRequest, userID uuid.UUID) *contract.Response { modelReq := &models.ListNotificationsRequest{ Page: req.Page, Limit: req.Limit, UserID: userID, IsRead: req.IsRead, } receivers, total, unreadCount, err := s.notificationProcessor.ListForUser(ctx, modelReq) if err != nil { errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error()) return contract.BuildErrorResponse([]*contract.ResponseError{errResp}) } totalPages := int(math.Ceil(float64(total) / float64(req.Limit))) response := contract.ListNotificationsResponse{ Notifications: transformer.NotificationReceiverModelResponsesToContracts(receivers), TotalCount: total, UnreadCount: unreadCount, Page: req.Page, Limit: req.Limit, TotalPages: totalPages, } return contract.BuildSuccessResponse(response) } func (s *NotificationServiceImpl) GetByID(ctx context.Context, id uuid.UUID) *contract.Response { resp, err := s.notificationProcessor.GetByID(ctx, id) if err != nil { errResp := contract.NewResponseError(constants.NotFoundErrorCode, constants.NotificationServiceEntity, err.Error()) return contract.BuildErrorResponse([]*contract.ResponseError{errResp}) } return contract.BuildSuccessResponse(transformer.NotificationModelResponseToContract(resp)) }