package pubsub

import (
	
	
	
	
	

	
)

const (
	MinBackoffDelay        = 100 * time.Millisecond
	MaxBackoffDelay        = 10 * time.Second
	TimeToLive             = 10 * time.Minute
	BackoffCleanupInterval = 1 * time.Minute
	BackoffMultiplier      = 2
	MaxBackoffJitterCoff   = 100
	MaxBackoffAttempts     = 4
)

type backoffHistory struct {
	duration  time.Duration
	lastTried time.Time
	attempts  int
}

type backoff struct {
	mu          sync.Mutex
	info        map[peer.ID]*backoffHistory
	ct          int           // size threshold that kicks off the cleaner
	ci          time.Duration // cleanup intervals
	maxAttempts int           // maximum backoff attempts prior to ejection
}

func newBackoff( context.Context,  int,  time.Duration,  int) *backoff {
	 := &backoff{
		mu:          sync.Mutex{},
		ct:          ,
		ci:          ,
		maxAttempts: ,
		info:        make(map[peer.ID]*backoffHistory),
	}

	go .cleanupLoop()

	return 
}

func ( *backoff) ( peer.ID) (time.Duration, error) {
	.mu.Lock()
	defer .mu.Unlock()

	,  := .info[]
	switch {
	case ! || time.Since(.lastTried) > TimeToLive:
		// first request goes immediately.
		 = &backoffHistory{
			duration: time.Duration(0),
			attempts: 0,
		}
	case .attempts >= .maxAttempts:
		return 0, fmt.Errorf("peer %s has reached its maximum backoff attempts", )

	case .duration < MinBackoffDelay:
		.duration = MinBackoffDelay

	case .duration < MaxBackoffDelay:
		 := rand.Intn(MaxBackoffJitterCoff)
		.duration = (BackoffMultiplier * .duration) + time.Duration()*time.Millisecond
		if .duration > MaxBackoffDelay || .duration < 0 {
			.duration = MaxBackoffDelay
		}
	}

	.attempts += 1
	.lastTried = time.Now()
	.info[] = 
	return .duration, nil
}

func ( *backoff) () {
	.mu.Lock()
	defer .mu.Unlock()

	for ,  := range .info {
		if time.Since(.lastTried) > TimeToLive {
			delete(.info, )
		}
	}
}

func ( *backoff) ( context.Context) {
	 := time.NewTicker(.ci)
	defer .Stop()

	for {
		select {
		case <-.Done():
			return // pubsub shutting down
		case <-.C:
			.cleanup()
		}
	}
}