package jitter

import (
	"math/rand"
	"time"
)

type Distribution interface {
	delta(rand *rand.Rand) time.Duration
}

var _ Distribution = Constant(0)

type Constant time.Duration

func (c Constant) delta(rand *rand.Rand) time.Duration {
	return time.Duration(c)
}

var _ Distribution = Linear{}

type Linear struct {
	Min time.Duration
	Max time.Duration
}

func (l Linear) delta(rand *rand.Rand) time.Duration {
	delta := l.Max - l.Min
	if delta > 0 {
		return l.Min + time.Duration(rand.Int63n(int64(delta)))
	}
	return l.Min
}

// DistributionForMidpoint returns a Linear distribution with a midpoint and a jitter ratio
// It is a convenience method for calculating (midpoint * (1 - ratio/2), midpoint * (1 + ratio/2))
func DistributionForMidpointAndRatio(midpoint time.Duration, ratio float64) Linear {
	halfWidth := time.Duration(float64(midpoint) * (ratio / 2.0))
	return Linear{
		Min: midpoint - halfWidth,
		Max: midpoint + halfWidth,
	}
}
