func (w WindowMetadata) getBurnRateFactor(totalWindow time.Duration, errorBudgetPercent float64, consumptionWindow time.Duration) float64 {
	hoursRequiredConsumption := errorBudgetPercent * totalWindow.Hours() / 100
	speed := hoursRequiredConsumption / consumptionWindow.Hours()
	return speed
}
getBurnRateFactor calculates the burnRateFactor (speed) needed to consume all the error budget available percent
in a specific time window taking into account the total time window.
package alert
import (
	"context"
	"fmt"
	"time"
)
type Severity int
const (
	UnknownAlertSeverity Severity = iota
	PageAlertSeverity
	TicketAlertSeverity
)
func (s Severity) String() string {
	switch s {
	case PageAlertSeverity:
		return "page"
	case TicketAlertSeverity:
		return "ticket"
	default:
		return "unknown"
	}
}
type MWMBAlert struct {
	ID             string
	ShortWindow    time.Duration
	LongWindow     time.Duration
	BurnRateFactor float64
	ErrorBudget    float64
	Severity       Severity
}
type MWMBAlertGroup struct {
	PageQuick   MWMBAlert
	PageSlow    MWMBAlert
	TicketQuick MWMBAlert
	TicketSlow  MWMBAlert
}
type generator bool
const AlertGenerator = generator(false)
type SLO struct {
	ID         string
	TimeWindow time.Duration
	Objective  float64
}
var windowMetadataCatalog = map[time.Duration]WindowMetadata{
	28 * 24 * time.Hour: newMonthWindowMetadata(28 * 24 * time.Hour),
	30 * 24 * time.Hour: newMonthWindowMetadata(30 * 24 * time.Hour),
}
func (g generator) GenerateMWMBAlerts(ctx context.Context, slo SLO) (*MWMBAlertGroup, error) {
	windowMeta, ok := windowMetadataCatalog[slo.TimeWindow]
	if !ok {
		return nil, fmt.Errorf("the %s SLO period time window is not supported", slo.TimeWindow)
	}
	errorBudget := 100 - slo.Objective
	group := MWMBAlertGroup{
		PageQuick: MWMBAlert{
			ID:             fmt.Sprintf("%s-page-quick", slo.ID),
			ShortWindow:    windowMeta.WindowPageQuickShort,
			LongWindow:     windowMeta.WindowPageQuickLong,
			BurnRateFactor: windowMeta.GetSpeedPageQuick(),
			ErrorBudget:    errorBudget,
			Severity:       PageAlertSeverity,
		},
		PageSlow: MWMBAlert{
			ID:             fmt.Sprintf("%s-page-slow", slo.ID),
			ShortWindow:    windowMeta.WindowPageSlowShort,
			LongWindow:     windowMeta.WindowPageSlowLong,
			BurnRateFactor: windowMeta.GetSpeedPageSlow(),
			ErrorBudget:    errorBudget,
			Severity:       PageAlertSeverity,
		},
		TicketQuick: MWMBAlert{
			ID:             fmt.Sprintf("%s-ticket-quick", slo.ID),
			ShortWindow:    windowMeta.WindowTicketQuickShort,
			LongWindow:     windowMeta.WindowTicketQuickLong,
			BurnRateFactor: windowMeta.GetSpeedTicketQuick(),
			ErrorBudget:    errorBudget,
			Severity:       TicketAlertSeverity,
		},
		TicketSlow: MWMBAlert{
			ID:             fmt.Sprintf("%s-ticket-slow", slo.ID),
			ShortWindow:    windowMeta.WindowTicketSlowShort,
			LongWindow:     windowMeta.WindowTicketSlowLong,
			BurnRateFactor: windowMeta.GetSpeedTicketSlow(),
			ErrorBudget:    errorBudget,
			Severity:       TicketAlertSeverity,
		},
	}
	return &group, nil
}
type WindowMetadata struct {
	WindowPeriod time.Duration
	WindowPageQuickShort   time.Duration
	WindowPageQuickLong    time.Duration
	WindowPageSlowShort    time.Duration
	WindowPageSlowLong     time.Duration
	WindowTicketQuickShort time.Duration
	WindowTicketQuickLong  time.Duration
	WindowTicketSlowShort  time.Duration
	WindowTicketSlowLong   time.Duration
	ErrorBudgetPercPageQuick   float64
	ErrorBudgetPercPageSlow    float64
	ErrorBudgetPercTicketQuick float64
	ErrorBudgetPercTicketSlow  float64
}
func (w WindowMetadata) GetSpeedPageQuick() float64 {
	return w.getBurnRateFactor(w.WindowPeriod, w.ErrorBudgetPercPageQuick, w.WindowPageQuickLong)
}
func (w WindowMetadata) GetSpeedPageSlow() float64 {
	return w.getBurnRateFactor(w.WindowPeriod, w.ErrorBudgetPercPageSlow, w.WindowPageSlowLong)
}
func (w WindowMetadata) GetSpeedTicketQuick() float64 {
	return w.getBurnRateFactor(w.WindowPeriod, w.ErrorBudgetPercTicketQuick, w.WindowTicketQuickLong)
}
func (w WindowMetadata) GetSpeedTicketSlow() float64 {
	return w.getBurnRateFactor(w.WindowPeriod, w.ErrorBudgetPercTicketSlow, w.WindowTicketSlowLong)
}