package httpserver import ( "context" "os" "time" "log" // "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" betSvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet" eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event" oddssvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" resultsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli" "github.com/robfig/cron/v3" "go.uber.org/zap" ) func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.ServiceImpl, resultService *resultsvc.Service, mongoLogger *zap.Logger) { c := cron.New(cron.WithSeconds()) schedule := []struct { spec string task func() }{ // { // spec: "0 0 * * * *", // Every 1 hour // task: func() { // mongoLogger.Info("Began fetching upcoming events cron task") // if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { // mongoLogger.Error("Failed to fetch upcoming events", // zap.Error(err), // ) // } else { // mongoLogger.Info("Completed fetching upcoming events without errors") // } // }, // }, // { // spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) // task: func() { // mongoLogger.Info("Began fetching non live odds cron task") // if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { // mongoLogger.Error("Failed to fetch non live odds", // zap.Error(err), // ) // } else { // mongoLogger.Info("Completed fetching non live odds without errors") // } // }, // }, { spec: "0 */5 * * * *", // Every 5 Minutes task: func() { mongoLogger.Info("Began update all expired events status cron task") if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil { mongoLogger.Error("Failed to update expired events status", zap.Error(err), ) } else { mongoLogger.Info("Completed expired events without errors") } }, }, // { // spec: "0 */15 * * * *", // Every 15 Minutes // task: func() { // mongoLogger.Info("Began fetching results for upcoming events cron task") // if err := resultService.FetchAndProcessResults(context.Background()); err != nil { // mongoLogger.Error("Failed to process result", // zap.Error(err), // ) // } else { // mongoLogger.Info("Completed processing all event result outcomes without errors") // } // }, // }, { spec: "0 0 * * * *", // Every Day task: func() { mongoLogger.Info("Began Send daily result notification cron task") if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-24*time.Hour)); err != nil { mongoLogger.Error("Failed to process result", zap.Error(err), ) } else { mongoLogger.Info("Completed sending daily result notification without errors") } }, }, } for _, job := range schedule { // job.task() if _, err := c.AddFunc(job.spec, job.task); err != nil { mongoLogger.Error("Failed to schedule data fetching cron job", zap.Error(err), ) } } c.Start() log.Println("Cron jobs started for event and odds services") mongoLogger.Info("Cron jobs started for event and odds services") } func StartTicketCrons(ticketService ticket.Service, mongoLogger *zap.Logger) { c := cron.New(cron.WithSeconds()) schedule := []struct { spec string task func() }{ { spec: "0 0 * * * *", // Every hour task: func() { mongoLogger.Info("Deleting old tickets") if err := ticketService.DeleteOldTickets(context.Background()); err != nil { mongoLogger.Error("Failed to remove old ticket", zap.Error(err), ) } else { mongoLogger.Info("Successfully deleted old tickets") } }, }, } for _, job := range schedule { if _, err := c.AddFunc(job.spec, job.task); err != nil { mongoLogger.Error("Failed to schedule ticket cron job", zap.Error(err), ) } } c.Start() mongoLogger.Info("Cron jobs started for ticket service") } // SetupReportCronJobs schedules periodic report generation func SetupReportandVirtualGameCronJobs( ctx context.Context, reportService *report.Service, virtualGameService *veli.Service, // inject your virtual game service outputDir string, ) { c := cron.New(cron.WithSeconds()) // use WithSeconds for testing schedule := []struct { spec string period string }{ { spec: "*/60 * * * * *", // Every 1 minute for testing period: "test", }, { spec: "0 0 0 * * *", // Daily at midnight period: "daily", }, { spec: "0 0 1 * * 0", // Weekly: Sunday at 1 AM period: "weekly", }, { spec: "0 0 2 1 * *", // Monthly: 1st day of month at 2 AM period: "monthly", }, } for _, job := range schedule { period := job.period if _, err := c.AddFunc(job.spec, func() { now := time.Now() var from, to time.Time switch period { case "daily": from = time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location()) to = time.Date(now.Year(), now.Month(), now.Day()-1, 23, 59, 59, 0, now.Location()) case "weekly": weekday := int(now.Weekday()) daysSinceSunday := (weekday + 7) % 7 from = time.Date(now.Year(), now.Month(), now.Day()-daysSinceSunday-7, 0, 0, 0, 0, now.Location()) to = from.AddDate(0, 0, 6).Add(time.Hour*23 + time.Minute*59 + time.Second*59) case "monthly": firstOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) from = firstOfMonth.AddDate(0, -1, 0) to = firstOfMonth.Add(-time.Second) default: log.Printf("Unknown period: %s", period) // return } // --- Generate Reports (skip for test) --- if period != "test" { log.Printf("Running %s report for period %s -> %s", period, from.Format(time.RFC3339), to.Format(time.RFC3339)) if err := reportService.GenerateReport(ctx, from, to); err != nil { log.Printf("Error generating %s report: %v", period, err) } else { log.Printf("Successfully generated %s report", period) } } // --- Fetch and Add Virtual Game Providers (daily + test) --- if period == "daily" || period == "test" { log.Printf("Fetching and adding virtual game providers (%s)...", period) brandID := os.Getenv("VELI_BRAND_ID") if brandID == "" { log.Println("VELI_BRAND_ID not set, skipping provider sync") return } page := 1 size := 1000 for { req := domain.ProviderRequest{ BrandID: brandID, ExtraData: true, Size: int(size), Page: int(page), } res, err := virtualGameService.AddProviders(ctx, req) if err != nil { log.Printf("Error adding virtual game providers on page %d: %v", page, err) break } log.Printf("[%s] Successfully processed page %d: %d providers", period, page, len(res.Items)) if len(res.Items) < size { // Last page reached break } page++ } log.Printf("[%s] Finished fetching and adding virtual game providers", period) } }); err != nil { log.Fatalf("Failed to schedule %s cron job: %v", period, err) } } c.Start() log.Printf("Cron jobs started. Reports will be saved to: %s", outputDir) } func ProcessBetCashback(ctx context.Context, betService *betSvc.Service) { c := cron.New(cron.WithSeconds()) schedule := []struct { spec string task func() }{ { spec: "0 0 0 * * *", // Daily at midnight task: func() { log.Println("process bet cashbacks...") if err := betService.ProcessBetCashback(ctx); err != nil { log.Printf("Failed to process bet cashbacks: %v", err) } else { log.Printf("Successfully processed bet cashbacks") } }, }, } for _, job := range schedule { if _, err := c.AddFunc(job.spec, job.task); err != nil { log.Fatalf("Failed to schedule cron job: %v", err) } } c.Start() log.Println("Cron jobs started for bet cashbacks") }