package cleaners

import (
	"sync"
	"time"

	"github.com/rs/zerolog/log"
)

type CleanerManager struct {
	activeCleaners    map[string]bool
	activeCleanerLock sync.Mutex
	exitChans         []chan any
}

var cleanerBuilders = []func() (onTick func(time.Time), name string, tickSpeed time.Duration){}

func NewManager() *CleanerManager {
	activeCleaners := make(map[string]bool)
	exitChans := []chan any{}
	cm := &CleanerManager{
		activeCleaners: activeCleaners,
		exitChans:      exitChans,
	}

	// Launch all cleaner tickers in a new goroutine each
	for _, builder := range cleanerBuilders {
		exitChan := make(chan any, 1)
		onTick, name, tickSpeed := builder()
		cm.exitChans = append(cm.exitChans, exitChan)
		log.Info().Str("name", name).Msg("Starting ticker for cleaner")
		go cm.tickOrExit(tickSpeed, name, exitChan, onTick)
	}

	return cm
}

func (m *CleanerManager) Stop() {
	for _, exitChan := range m.exitChans {
		exitChan <- 1
	}
}

func (m *CleanerManager) tickOrExit(
	tickSpeed time.Duration,
	name string,
	exitChan chan any,
	onTick func(time.Time),
) {
	ticker := time.Tick(tickSpeed)
	for {
		select {
		case now := <-ticker:
			go m.wrapOnTick(name, now, onTick)
		case <-exitChan:
			return
		}
	}
}

func (m *CleanerManager) wrapOnTick(name string, now time.Time, onTick func(time.Time)) {
	m.activeCleanerLock.Lock()
	if m.activeCleaners[name] {
		m.activeCleanerLock.Unlock()
		return
	}
	m.activeCleaners[name] = true
	m.activeCleanerLock.Unlock()
	log.Info().Str("cleaner", name).Msg("Ticking cleaner")
	onTick(now)
	m.activeCleanerLock.Lock()
	m.activeCleaners[name] = false
	m.activeCleanerLock.Unlock()
}
