package scheduler

import (
	"context"
	"log/slog"
	"time"

	"github.com/cereda-systems/nexus-scanner/internal/module"
)

// Scheduler runs registered modules at their configured intervals.
type Scheduler struct {
	registry *module.Registry
}

// New returns a new Scheduler backed by the given registry.
func New(registry *module.Registry) *Scheduler {
	return &Scheduler{registry: registry}
}

// Run starts all modules in background goroutines and blocks until ctx is cancelled.
func (s *Scheduler) Run(ctx context.Context) {
	for _, m := range s.registry.All() {
		go s.runModule(ctx, m)
	}
	<-ctx.Done()
}

func (s *Scheduler) runModule(ctx context.Context, m module.Module) {
	log := slog.With("module", m.Name())

	// Run immediately on startup.
	s.execute(ctx, m, log)

	// If interval is zero, run once and stop.
	if m.Interval() == 0 {
		return
	}

	ticker := time.NewTicker(m.Interval())
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			s.execute(ctx, m, log)
		}
	}
}

func (s *Scheduler) execute(ctx context.Context, m module.Module, log *slog.Logger) {
	log.Info("run started")
	start := time.Now()

	if err := m.Run(ctx); err != nil {
		log.Error("run failed", "err", err, "elapsed", time.Since(start).Round(time.Millisecond))
		return
	}

	log.Info("run completed", "elapsed", time.Since(start).Round(time.Millisecond))
}
