package cron

import (
	"context"
	"primesys_email/src/alert"
	"primesys_email/src/logger"
	"primesys_email/src/mail"
	services "primesys_email/src/services/report_email_service"
	"primesys_email/src/utils"
	"time"

	"github.com/robfig/cron/v3"
)

const (
	// every day at 12:05 AM IST
	dailyQueueSpec = "5 0 * * *"
	// every hour at minute 0
	hourlyDeliverySpec = "0 * * * *"
)

// notifier mails the errors of each run, it may be nil
func Start(url string, sender *mail.DynamicMailSender, runDeliveryNow bool, notifier *alert.Notifier) (*cron.Cron, error) {

	c := cron.New(
		cron.WithLocation(utils.ISTLocation()),
		cron.WithChain(cron.Recover(cron.DefaultLogger), cron.SkipIfStillRunning(cron.DefaultLogger)),
	)

	queueID, err := c.AddFunc(dailyQueueSpec, func() {
		dailyQueueJob()
		notifier.Flush("Daily queue job")
	})
	if err != nil {
		return nil, err
	}

	deliveryID, err := c.AddFunc(hourlyDeliverySpec, func() {
		hourlyDeliveryJob(url, sender)
		notifier.Flush("Hourly delivery job")
	})
	if err != nil {
		return nil, err
	}

	c.Start()
	logger.Info("Cron started, queue job next run %v, delivery job next run %v", c.Entry(queueID).Next, c.Entry(deliveryID).Next)

	if runDeliveryNow {
		logger.Info("Running delivery job now")
		// wrapped job, so it is skipped if the hourly run is already running
		go c.Entry(deliveryID).WrappedJob.Run()
	}
	return c, nil
}

func dailyQueueJob() {
	logger.Info("Daily queue cron started")

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
	defer cancel()

	if err := services.QueueDailyReports(ctx); err != nil {
		logger.Error("Daily queue cron failed : %v", err)
		return
	}

	logger.Info("Daily queue cron completed")
}

func hourlyDeliveryJob(url string, sender *mail.DynamicMailSender) {
	logger.Info("Hourly delivery cron started")

	// finish before the next hourly run
	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Minute)
	defer cancel()

	if err := services.DivisionEmailDelivery(ctx, url, sender); err != nil {
		logger.Error("Hourly delivery cron failed : %v", err)
		return
	}

	logger.Info("Hourly delivery cron completed")
}
