package notification import ( "github.com/asaskevich/govalidator" ) // EventType represents the type of notification event type EventType string const ( EventTypeEmail EventType = "EMAIL" EventTypeSMS EventType = "SMS" EventTypePush EventType = "PUSH" EventTypeOTP EventType = "OTP" ) // NotificationMethods contains different delivery methods for notifications type NotificationMethods struct { OTP string `json:"otp,omitempty" valid:"optional"` SMS string `json:"sms,omitempty" valid:"optional"` Push string `json:"push,omitempty" valid:"optional"` Email string `json:"email,omitempty" valid:"optional,email"` } // NotificationRequest represents the request structure for sending notifications type NotificationRequest struct { UserID string `json:"user_id,omitempty" valid:"optional"` Title string `json:"title" valid:"required"` Message string `json:"message" valid:"required,length(1|1000)"` Type string `json:"type" valid:"required,in(info|warning|alert|reject)"` EventType EventType `json:"event_type" valid:"required,in(EMAIL|SMS|PUSH|OTP)"` Priority string `json:"priority" valid:"required,in(low|medium|important)"` ScheduledAt int64 `json:"scheduled_at"` Metadata map[string]any `json:"metadata,omitempty" valid:"optional"` Methods NotificationMethods `json:"methods" valid:"required"` } // NotificationResponse represents the successful response from notification service type NotificationResponse struct { Status string `json:"status"` } // NotificationErrorResponse represents the error response from notification service type NotificationErrorResponse struct { Error string `json:"error"` } // Validate validates the notification request func (nr *NotificationRequest) Validate() error { // First run govalidator validation if _, err := govalidator.ValidateStruct(nr); err != nil { return ErrValidation{Field: "struct", Message: err.Error()} } // Custom validation: ensure at least one method is provided based on event type switch nr.EventType { case EventTypeEmail: if nr.Methods.Email == "" { return ErrValidation{Field: "methods.email", Message: "email address is required for EMAIL event type"} } case EventTypeSMS: if nr.Methods.SMS == "" { return ErrValidation{Field: "methods.sms", Message: "SMS number is required for SMS event type"} } case EventTypePush: if nr.Methods.Push == "" { return ErrValidation{Field: "methods.push", Message: "push device token is required for PUSH event type"} } case EventTypeOTP: if nr.Methods.OTP == "" { return ErrValidation{Field: "methods.otp", Message: "OTP number is required for OTP event type"} } } // Validate scheduled_at: 0 means immediate delivery, otherwise must be future timestamp if nr.ScheduledAt < 0 { return ErrValidation{Field: "scheduled_at", Message: "scheduled_at cannot be negative"} } return nil } // HasMethod checks if a specific method is configured func (nm *NotificationMethods) HasMethod(eventType EventType) bool { switch eventType { case EventTypeEmail: return nm.Email != "" case EventTypeSMS: return nm.SMS != "" case EventTypePush: return nm.Push != "" case EventTypeOTP: return nm.OTP != "" default: return false } } // GetMethodValue returns the value for a specific method func (nm *NotificationMethods) GetMethodValue(eventType EventType) string { switch eventType { case EventTypeEmail: return nm.Email case EventTypeSMS: return nm.SMS case EventTypePush: return nm.Push case EventTypeOTP: return nm.OTP default: return "" } } // IsImmediate returns true if the notification should be sent immediately (scheduled_at = 0) func (nr *NotificationRequest) IsImmediate() bool { return nr.ScheduledAt == 0 }