package jobs import ( "time" ) // ReminderConfig represents the configuration for reminder scheduling type ReminderConfig struct { // Default reminder times before the meeting (in minutes) DefaultReminders []int `json:"default_reminders"` // Maximum number of reminders per booking MaxReminders int `json:"max_reminders"` // Minimum time before meeting to send reminder (in minutes) MinReminderTime int `json:"min_reminder_time"` // Whether reminders are enabled globally Enabled bool `json:"enabled"` } // DefaultReminderConfig returns the default reminder configuration func DefaultReminderConfig() *ReminderConfig { return &ReminderConfig{ DefaultReminders: []int{1440, 60, 15}, // 24 hours, 1 hour, 15 minutes before MaxReminders: 3, MinReminderTime: 5, // Don't send reminders less than 5 minutes before Enabled: true, } } // ReminderScheduler handles the scheduling of reminder notifications type ReminderScheduler struct { config *ReminderConfig jobScheduler *JobScheduler } // NewReminderScheduler creates a new reminder scheduler func NewReminderScheduler(config *ReminderConfig, jobScheduler *JobScheduler) *ReminderScheduler { if config == nil { config = DefaultReminderConfig() } return &ReminderScheduler{ config: config, jobScheduler: jobScheduler, } } // ScheduleRemindersForBooking schedules all reminders for a booking func (rs *ReminderScheduler) ScheduleRemindersForBooking(bookingID uint, userID uint, meetingTime time.Time) error { if !rs.config.Enabled { return nil } now := time.Now() scheduledCount := 0 for _, reminderMinutes := range rs.config.DefaultReminders { if scheduledCount >= rs.config.MaxReminders { break } reminderTime := meetingTime.Add(-time.Duration(reminderMinutes) * time.Minute) // Skip if reminder time is in the past if reminderTime.Before(now) { continue } // Skip if reminder is too close to the meeting if meetingTime.Sub(reminderTime).Minutes() < float64(rs.config.MinReminderTime) { continue } // Schedule the reminder job rs.jobScheduler.ScheduleReminderJob(bookingID, userID, reminderTime) scheduledCount++ } return nil } // CancelRemindersForBooking cancels all scheduled reminders for a booking func (rs *ReminderScheduler) CancelRemindersForBooking(bookingID uint) error { // In a production system, this would mark the reminders as cancelled in a persistent store // For now, we'll just log the cancellation // The actual implementation would depend on how jobs are persisted return nil } // UpdateReminderConfig updates the reminder configuration func (rs *ReminderScheduler) UpdateReminderConfig(config *ReminderConfig) { rs.config = config } // GetReminderConfig returns the current reminder configuration func (rs *ReminderScheduler) GetReminderConfig() *ReminderConfig { return rs.config } // GetNextReminderTime calculates the next reminder time for a meeting func (rs *ReminderScheduler) GetNextReminderTime(meetingTime time.Time) *time.Time { if !rs.config.Enabled { return nil } now := time.Now() for _, reminderMinutes := range rs.config.DefaultReminders { reminderTime := meetingTime.Add(-time.Duration(reminderMinutes) * time.Minute) if reminderTime.After(now) { return &reminderTime } } return nil } // IsReminderTimeValid checks if a reminder time is valid func (rs *ReminderScheduler) IsReminderTimeValid(reminderTime, meetingTime time.Time) bool { if !rs.config.Enabled { return false } // Check if reminder is in the future if reminderTime.Before(time.Now()) { return false } // Check if reminder is not too close to the meeting timeDiff := meetingTime.Sub(reminderTime).Minutes() if timeDiff < float64(rs.config.MinReminderTime) { return false } return true }