package throttling

import (
	"time"
)

// Throttling notifications to prometheus and web clients
// TO be used in a single-threaded manner.
type Throttler[T any] struct {
	minDelay time.Duration
	// ucntion to call to implement the notification.
	notifier         func(t *T)
	lastReportedTime time.Time
	pendingValue     *T
}

func NewThrottler[T any](notifier func(t *T), minDelay time.Duration) Throttler[T] {
	throttler := Throttler[T]{
		minDelay:         minDelay,
		notifier:         notifier,
		lastReportedTime: time.Time{},
		pendingValue:     nil,
	}
	return throttler
}

// Notify there is a new value. Performs notification if it was long enough ago
// for the last notification to be sent. If not, it is stored as a pending event to
// be sent later. New events that come in before a notification is sent override the
// pending event.
func (throttler *Throttler[T]) Notify(value *T) {
	if clock.time().Sub(throttler.lastReportedTime) >= throttler.minDelay {
		throttler.notifier(value)
		throttler.lastReportedTime = clock.time()
		throttler.pendingValue = nil
		return
	}
	throttler.pendingValue = value
}

// To be called periodically. It sends out any pending events if the time the last
// notification was sent is long enough ago.
func (throttler *Throttler[T]) Ping() {
	if throttler.pendingValue != nil {
		throttler.Notify(throttler.pendingValue)
	}
}