package autonat

import (
	
	

	
	
)

// config holds configurable options for the autonat subsystem.
type config struct {
	host host.Host

	addressFunc       AddrFunc
	dialPolicy        dialPolicy
	dialer            network.Network
	forceReachability bool
	reachability      network.Reachability
	metricsTracer     MetricsTracer

	// client
	bootDelay          time.Duration
	retryInterval      time.Duration
	refreshInterval    time.Duration
	requestTimeout     time.Duration
	throttlePeerPeriod time.Duration

	// server
	dialTimeout         time.Duration
	maxPeerAddresses    int
	throttleGlobalMax   int
	throttlePeerMax     int
	throttleResetPeriod time.Duration
	throttleResetJitter time.Duration
}

var defaults = func( *config) error {
	.bootDelay = 15 * time.Second
	.retryInterval = 90 * time.Second
	.refreshInterval = 15 * time.Minute
	.requestTimeout = 30 * time.Second
	.throttlePeerPeriod = 90 * time.Second

	.dialTimeout = 15 * time.Second
	.maxPeerAddresses = 16
	.throttleGlobalMax = 30
	.throttlePeerMax = 3
	.throttleResetPeriod = 1 * time.Minute
	.throttleResetJitter = 15 * time.Second
	return nil
}

const maxRefreshInterval = 24 * time.Hour

// EnableService specifies that AutoNAT should be allowed to run a NAT service to help
// other peers determine their own NAT status. The provided Network should not be the
// default network/dialer of the host passed to `New`, as the NAT system will need to
// make parallel connections, and as such will modify both the associated peerstore
// and terminate connections of this dialer. The dialer provided
// should be compatible (TCP/UDP) however with the transports of the libp2p network.
func ( network.Network) Option {
	return func( *config) error {
		if  == .host.Network() || .Peerstore() == .host.Peerstore() {
			return errors.New("dialer should not be that of the host")
		}
		.dialer = 
		return nil
	}
}

// WithReachability overrides autonat to simply report an over-ridden reachability
// status.
func ( network.Reachability) Option {
	return func( *config) error {
		.forceReachability = true
		.reachability = 
		return nil
	}
}

// UsingAddresses allows overriding which Addresses the AutoNAT client believes
// are "its own". Useful for testing, or for more exotic port-forwarding
// scenarios where the host may be listening on different ports than it wants
// to externally advertise or verify connectability on.
func ( AddrFunc) Option {
	return func( *config) error {
		if  == nil {
			return errors.New("invalid address function supplied")
		}
		.addressFunc = 
		return nil
	}
}

// WithSchedule configures how aggressively probes will be made to verify the
// address of the host. retryInterval indicates how often probes should be made
// when the host lacks confidence about its address, while refreshInterval
// is the schedule of periodic probes when the host believes it knows its
// steady-state reachability.
func (,  time.Duration) Option {
	return func( *config) error {
		.retryInterval = 
		.refreshInterval = 
		return nil
	}
}

// WithoutStartupDelay removes the initial delay the NAT subsystem typically
// uses as a buffer for ensuring that connectivity and guesses as to the hosts
// local interfaces have settled down during startup.
func () Option {
	return func( *config) error {
		.bootDelay = 1
		return nil
	}
}

// WithoutThrottling indicates that this autonat service should not place
// restrictions on how many peers it is willing to help when acting as
// a server.
func () Option {
	return func( *config) error {
		.throttleGlobalMax = 0
		return nil
	}
}

// WithThrottling specifies how many peers (`amount`) it is willing to help
// ever `interval` amount of time when acting as a server.
func ( int,  time.Duration) Option {
	return func( *config) error {
		.throttleGlobalMax = 
		.throttleResetPeriod = 
		.throttleResetJitter =  / 4
		return nil
	}
}

// WithPeerThrottling specifies a limit for the maximum number of IP checks
// this node will provide to an individual peer in each `interval`.
func ( int) Option {
	return func( *config) error {
		.throttlePeerMax = 
		return nil
	}
}

// WithMetricsTracer uses mt to track autonat metrics
func ( MetricsTracer) Option {
	return func( *config) error {
		.metricsTracer = 
		return nil
	}
}