package scheduler

import (
	"sync"
)

// Assign elements to a bucket and perform an action 12 cycles later. This can be
// used in conjunction with a cron job to perform cleanup tasks at a constant point
// in the future.
type Bucket[T any] struct {
	elements [12][]T
	bucket   int
	mutex    sync.Mutex
}

type BucketInterface[T any] interface {
	Process(handler func(element Bucket[T]))
	Schedule(element T) error
	clear()
	lapse()
}

// Run a callback on each element in next bucket, then clear
func (e *Bucket[T]) Process(handler func(element T)) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	e.lapse()
	if len(e.elements[e.bucket]) > 0 {
		for _, element := range e.elements[e.bucket] {
			handler(element)
		}
		e.clear()
	}
}

// Add element to a bucket to be deleted later
func (e *Bucket[T]) Schedule(element T) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	e.elements[e.bucket] = append(e.elements[e.bucket], element)
}

// Remove all elements from current bucket
func (e *Bucket[T]) clear() {
	e.elements[e.bucket] = []T{}
}

// Increment the active bucket
func (e *Bucket[T]) lapse() {
	e.bucket += 1
	e.bucket %= len(e.elements)
}
