package backoff

import (
	
	
	

	
	

	lru 
)

// BackoffConnector is a utility to connect to peers, but only if we have not recently tried connecting to them already
type BackoffConnector struct {
	cache      *lru.TwoQueueCache[peer.ID, *connCacheData]
	host       host.Host
	connTryDur time.Duration
	backoff    BackoffFactory
	mux        sync.Mutex
}

// NewBackoffConnector creates a utility to connect to peers, but only if we have not recently tried connecting to them already
// cacheSize is the size of a TwoQueueCache
// connectionTryDuration is how long we attempt to connect to a peer before giving up
// backoff describes the strategy used to decide how long to backoff after previously attempting to connect to a peer
func ( host.Host,  int,  time.Duration,  BackoffFactory) (*BackoffConnector, error) {
	,  := lru.New2Q[peer.ID, *connCacheData]()
	if  != nil {
		return nil, 
	}

	return &BackoffConnector{
		cache:      ,
		host:       ,
		connTryDur: ,
		backoff:    ,
	}, nil
}

type connCacheData struct {
	nextTry time.Time
	strat   BackoffStrategy
}

// Connect attempts to connect to the peers passed in by peerCh. Will not connect to peers if they are within the backoff period.
// As Connect will attempt to dial peers as soon as it learns about them, the caller should try to keep the number,
// and rate, of inbound peers manageable.
func ( *BackoffConnector) ( context.Context,  <-chan peer.AddrInfo) {
	for {
		select {
		case ,  := <-:
			if ! {
				return
			}

			if .ID == .host.ID() || .ID == "" {
				continue
			}

			.mux.Lock()
			var  *connCacheData
			if ,  := .cache.Get(.ID);  {
				 := time.Now()
				if .Before(.nextTry) {
					.mux.Unlock()
					continue
				}

				.nextTry = .Add(.strat.Delay())
			} else {
				 = &connCacheData{strat: .backoff()}
				.nextTry = time.Now().Add(.strat.Delay())
				.cache.Add(.ID, )
			}
			.mux.Unlock()

			go func( peer.AddrInfo) {
				,  := context.WithTimeout(, .connTryDur)
				defer ()

				 := .host.Connect(, )
				if  != nil {
					log.Debugf("Error connecting to pubsub peer %s: %s", .ID, .Error())
					return
				}
			}()

		case <-.Done():
			log.Infof("discovery: backoff connector context error %v", .Err())
			return
		}
	}
}