package worker

import (
	"time"

	"code.justin.tv/creator-collab/log/errors"
	"code.justin.tv/live/autohost/internal/worker/clock"
)

// liveChannelCheck is meant to guard against Multiplex returning a partial set of live channels due to a blip.
//
// If Autohost Worker acts on a partial set of live channels, it corrupts its state, erroneously hosting and unhosting
// many channels.
type liveChannelCheck struct {
	prevNumLiveChannels int
	prevFetchTime       time.Time
	clock               clock.Clock
}

func newLiveChannelCheck(clock clock.Clock) *liveChannelCheck {
	return &liveChannelCheck{
		clock: clock,
	}
}

// requireWithinThreshold takes the number of live channels returned by Multiplex, and compares it to the last
// good value it has. It returns an error if the number is over 10% smaller than the previous number.
// However it resets the threshold if the number is consistently smaller for over 2 minutes.
func (t *liveChannelCheck) requireWithinThreshold(numLiveChannels int) error {
	now := t.clock.Now()

	if !t.isWithinThreshold(numLiveChannels, now) {
		return errors.New("number of live channels from multiplex is over 10% less than previously fetched number", errors.Fields{
			"num_live_channels":      numLiveChannels,
			"prev_num_live_channels": t.prevNumLiveChannels,
			"prev_fetched_time":      t.prevFetchTime,
		})
	}

	t.prevFetchTime = now
	t.prevNumLiveChannels = numLiveChannels
	return nil
}

func (t *liveChannelCheck) isWithinThreshold(numLiveChannels int, now time.Time) bool {
	if now.Sub(t.prevFetchTime) > 2*time.Minute {
		return true
	}
	if numLiveChannels >= t.prevNumLiveChannels {
		return true
	}

	diff := float64(t.prevNumLiveChannels - numLiveChannels)
	prevNumLiveChannelsFloat := float64(t.prevNumLiveChannels)
	return diff*100/prevNumLiveChannelsFloat <= 10
}
