package autorelay

import (
	
	
	
	

	
	
	
	

	logging 
)

var log = logging.Logger("autorelay")

type AutoRelay struct {
	refCount  sync.WaitGroup
	ctx       context.Context
	ctxCancel context.CancelFunc

	mx     sync.Mutex
	status network.Reachability

	relayFinder *relayFinder

	host host.Host

	metricsTracer MetricsTracer
}

func ( host.Host,  ...Option) (*AutoRelay, error) {
	 := &AutoRelay{
		host:   ,
		status: network.ReachabilityUnknown,
	}
	 := defaultConfig
	for ,  := range  {
		if  := (&);  != nil {
			return nil, 
		}
	}
	.ctx, .ctxCancel = context.WithCancel(context.Background())
	,  := newRelayFinder(, &)
	if  != nil {
		return nil, fmt.Errorf("failed to create autorelay: %w", )
	}
	.relayFinder = 
	.metricsTracer = &wrappedMetricsTracer{.metricsTracer}

	return , nil
}

func ( *AutoRelay) () {
	.refCount.Add(1)
	go func() {
		defer .refCount.Done()
		.background()
	}()
}

func ( *AutoRelay) () {
	,  := .host.EventBus().Subscribe(new(event.EvtLocalReachabilityChanged), eventbus.Name("autorelay (background)"))
	if  != nil {
		log.Debug("failed to subscribe to the EvtLocalReachabilityChanged")
		return
	}
	defer .Close()

	for {
		select {
		case <-.ctx.Done():
			return
		case ,  := <-.Out():
			if ! {
				return
			}
			 := .(event.EvtLocalReachabilityChanged)
			switch .Reachability {
			case network.ReachabilityPrivate, network.ReachabilityUnknown:
				 := .relayFinder.Start()
				if errors.Is(, errAlreadyRunning) {
					log.Debug("tried to start already running relay finder")
				} else if  != nil {
					log.Errorw("failed to start relay finder", "error", )
				} else {
					.metricsTracer.RelayFinderStatus(true)
				}
			case network.ReachabilityPublic:
				.relayFinder.Stop()
				.metricsTracer.RelayFinderStatus(false)
			}
			.mx.Lock()
			.status = .Reachability
			.mx.Unlock()
		}
	}
}

func ( *AutoRelay) () error {
	.ctxCancel()
	 := .relayFinder.Stop()
	.refCount.Wait()
	return 
}