package autonat

import (
	

	
	
	
	
)

const metricNamespace = "libp2p_autonat"

var (
	reachabilityStatus = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Namespace: metricNamespace,
			Name:      "reachability_status",
			Help:      "Current node reachability",
		},
	)
	reachabilityStatusConfidence = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Namespace: metricNamespace,
			Name:      "reachability_status_confidence",
			Help:      "Node reachability status confidence",
		},
	)
	receivedDialResponseTotal = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: metricNamespace,
			Name:      "received_dial_response_total",
			Help:      "Count of dial responses for client",
		},
		[]string{"response_status"},
	)
	outgoingDialResponseTotal = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: metricNamespace,
			Name:      "outgoing_dial_response_total",
			Help:      "Count of dial responses for server",
		},
		[]string{"response_status"},
	)
	outgoingDialRefusedTotal = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: metricNamespace,
			Name:      "outgoing_dial_refused_total",
			Help:      "Count of dial requests refused by server",
		},
		[]string{"refusal_reason"},
	)
	nextProbeTimestamp = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Namespace: metricNamespace,
			Name:      "next_probe_timestamp",
			Help:      "Time of next probe",
		},
	)
	collectors = []prometheus.Collector{
		reachabilityStatus,
		reachabilityStatusConfidence,
		receivedDialResponseTotal,
		outgoingDialResponseTotal,
		outgoingDialRefusedTotal,
		nextProbeTimestamp,
	}
)

type MetricsTracer interface {
	ReachabilityStatus(status network.Reachability)
	ReachabilityStatusConfidence(confidence int)
	ReceivedDialResponse(status pb.Message_ResponseStatus)
	OutgoingDialResponse(status pb.Message_ResponseStatus)
	OutgoingDialRefused(reason string)
	NextProbeTime(t time.Time)
}

func getResponseStatus( pb.Message_ResponseStatus) string {
	var  string
	switch  {
	case pb.Message_OK:
		 = "ok"
	case pb.Message_E_DIAL_ERROR:
		 = "dial error"
	case pb.Message_E_DIAL_REFUSED:
		 = "dial refused"
	case pb.Message_E_BAD_REQUEST:
		 = "bad request"
	case pb.Message_E_INTERNAL_ERROR:
		 = "internal error"
	default:
		 = "unknown"
	}
	return 
}

const (
	rate_limited     = "rate limited"
	dial_blocked     = "dial blocked"
	no_valid_address = "no valid address"
)

type metricsTracer struct{}

var _ MetricsTracer = &metricsTracer{}

type metricsTracerSetting struct {
	reg prometheus.Registerer
}

type MetricsTracerOption func(*metricsTracerSetting)

func ( prometheus.Registerer) MetricsTracerOption {
	return func( *metricsTracerSetting) {
		if  != nil {
			.reg = 
		}
	}
}

func ( ...MetricsTracerOption) MetricsTracer {
	 := &metricsTracerSetting{reg: prometheus.DefaultRegisterer}
	for ,  := range  {
		()
	}
	metricshelper.RegisterCollectors(.reg, collectors...)
	return &metricsTracer{}
}

func ( *metricsTracer) ( network.Reachability) {
	reachabilityStatus.Set(float64())
}

func ( *metricsTracer) ( int) {
	reachabilityStatusConfidence.Set(float64())
}

func ( *metricsTracer) ( pb.Message_ResponseStatus) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()
	* = append(*, getResponseStatus())
	receivedDialResponseTotal.WithLabelValues(*...).Inc()
}

func ( *metricsTracer) ( pb.Message_ResponseStatus) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()
	* = append(*, getResponseStatus())
	outgoingDialResponseTotal.WithLabelValues(*...).Inc()
}

func ( *metricsTracer) ( string) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()
	* = append(*, )
	outgoingDialRefusedTotal.WithLabelValues(*...).Inc()
}

func ( *metricsTracer) ( time.Time) {
	nextProbeTimestamp.Set(float64(.Unix()))
}