package events import ( "context" "fmt" "log" "strconv" "time" "velox-bot/internal/db/services" "github.com/bwmarrin/discordgo" ) // StartScheduleReminderLoop runs a background loop that periodically checks for // upcoming sessions and sends DM reminders to all participants. func StartScheduleReminderLoop(s *discordgo.Session, svc *services.Services) { if svc == nil || svc.Schedule == nil || s == nil { return } const ( interval = time.Minute // check every minute remindBefore = 10 * time.Minute // remind 10 minutes before initialDelay = 10 * time.Second ) go func() { // small delay so the bot can fully start time.Sleep(initialDelay) ticker := time.NewTicker(interval) defer ticker.Stop() for range ticker.C { now := time.Now().UTC() ctx := context.Background() // Find all sessions that start in the next `remindBefore` window and haven't been reminded. schedules, err := svc.Schedule.ListDueForReminder(ctx, now, remindBefore) if err != nil { log.Printf("schedule: reminder query failed: %v", err) continue } for _, sch := range schedules { if sch == nil { continue } utcStr := sch.ScheduledAt.UTC().Format("2006-01-02 15:04") desc := sch.Description // Notify requester with local time if available. if svc.UserSettings != nil { locReq, zoneReq, _, err := svc.UserSettings.GetTimezone(ctx, sch.RequesterID) if err != nil { locReq = sch.ScheduledAt.UTC().Location() zoneReq = "UTC" } localReq := sch.ScheduledAt.In(locReq).Format("2006-01-02 15:04") base := fmt.Sprintf("Reminder: you have a scheduled session at %s UTC (%s %s) with <@%d>.", utcStr, localReq, zoneReq, sch.InviteeID) if desc != "" { base += "\nTopic: " + desc } if err := dmUser(s, sch.RequesterID, base); err != nil { log.Printf("schedule: failed to DM requester reminder: %v", err) } } // Notify invitee with their local time if available. if svc.UserSettings != nil { locInv, zoneInv, _, err := svc.UserSettings.GetTimezone(ctx, sch.InviteeID) if err != nil { locInv = sch.ScheduledAt.UTC().Location() zoneInv = "UTC" } localInv := sch.ScheduledAt.In(locInv).Format("2006-01-02 15:04") baseInvitee := fmt.Sprintf("Reminder: you have a scheduled session at %s UTC (%s %s) with <@%d>.", utcStr, localInv, zoneInv, sch.RequesterID) if desc != "" { baseInvitee += "\nTopic: " + desc } if err := dmUser(s, sch.InviteeID, baseInvitee); err != nil { log.Printf("schedule: failed to DM invitee reminder: %v", err) } } if err := svc.Schedule.MarkReminded(ctx, sch.ID); err != nil { log.Printf("schedule: failed to mark reminder sent for id=%d: %v", sch.ID, err) } } } }() } func dmUser(s *discordgo.Session, userID int64, content string) error { if s == nil || userID == 0 { return nil } uid := strconv.FormatInt(userID, 10) ch, err := s.UserChannelCreate(uid) if err != nil { return err } _, err = s.ChannelMessageSend(ch.ID, content) return err }