package identify

import (
	
	
	

	
)

const metricNamespace = "libp2p_identify"

var (
	pushesTriggered = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: metricNamespace,
			Name:      "identify_pushes_triggered_total",
			Help:      "Pushes Triggered",
		},
		[]string{"trigger"},
	)
	identify = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: metricNamespace,
			Name:      "identify_total",
			Help:      "Identify",
		},
		[]string{"dir"},
	)
	identifyPush = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: metricNamespace,
			Name:      "identify_push_total",
			Help:      "Identify Push",
		},
		[]string{"dir"},
	)
	connPushSupportTotal = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: metricNamespace,
			Name:      "conn_push_support_total",
			Help:      "Identify Connection Push Support",
		},
		[]string{"support"},
	)
	protocolsCount = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Namespace: metricNamespace,
			Name:      "protocols_count",
			Help:      "Protocols Count",
		},
	)
	addrsCount = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Namespace: metricNamespace,
			Name:      "addrs_count",
			Help:      "Address Count",
		},
	)
	numProtocolsReceived = prometheus.NewHistogram(
		prometheus.HistogramOpts{
			Namespace: metricNamespace,
			Name:      "protocols_received",
			Help:      "Number of Protocols received",
			Buckets:   buckets,
		},
	)
	numAddrsReceived = prometheus.NewHistogram(
		prometheus.HistogramOpts{
			Namespace: metricNamespace,
			Name:      "addrs_received",
			Help:      "Number of addrs received",
			Buckets:   buckets,
		},
	)
	collectors = []prometheus.Collector{
		pushesTriggered,
		identify,
		identifyPush,
		connPushSupportTotal,
		protocolsCount,
		addrsCount,
		numProtocolsReceived,
		numAddrsReceived,
	}
	// 1 to 20 and then up to 100 in steps of 5
	buckets = append(
		prometheus.LinearBuckets(1, 1, 20),
		prometheus.LinearBuckets(25, 5, 16)...,
	)
)

type MetricsTracer interface {
	// TriggeredPushes counts IdentifyPushes triggered by event
	TriggeredPushes(event any)

	// ConnPushSupport counts peers by Push Support
	ConnPushSupport(identifyPushSupport)

	// IdentifyReceived tracks metrics on receiving an identify response
	IdentifyReceived(isPush bool, numProtocols int, numAddrs int)

	// IdentifySent tracks metrics on sending an identify response
	IdentifySent(isPush bool, numProtocols int, numAddrs int)
}

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) ( any) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()

	 := "unknown"
	switch .(type) {
	case event.EvtLocalProtocolsUpdated:
		 = "protocols_updated"
	case event.EvtLocalAddressesUpdated:
		 = "addresses_updated"
	}
	* = append(*, )
	pushesTriggered.WithLabelValues(*...).Inc()
}

func ( *metricsTracer) ( identifyPushSupport) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()

	* = append(*, getPushSupport())
	connPushSupportTotal.WithLabelValues(*...).Inc()
}

func ( *metricsTracer) ( bool,  int,  int) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()

	if  {
		* = append(*, metricshelper.GetDirection(network.DirOutbound))
		identifyPush.WithLabelValues(*...).Inc()
	} else {
		* = append(*, metricshelper.GetDirection(network.DirInbound))
		identify.WithLabelValues(*...).Inc()
	}

	protocolsCount.Set(float64())
	addrsCount.Set(float64())
}

func ( *metricsTracer) ( bool,  int,  int) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()

	if  {
		* = append(*, metricshelper.GetDirection(network.DirInbound))
		identifyPush.WithLabelValues(*...).Inc()
	} else {
		* = append(*, metricshelper.GetDirection(network.DirOutbound))
		identify.WithLabelValues(*...).Inc()
	}

	numProtocolsReceived.Observe(float64())
	numAddrsReceived.Observe(float64())
}

func ( *metricsTracer) ( identifyPushSupport) {
	 := metricshelper.GetStringSlice()
	defer metricshelper.PutStringSlice()

	* = append(*, getPushSupport())
	connPushSupportTotal.WithLabelValues(*...).Inc()
}

func getPushSupport( identifyPushSupport) string {
	switch  {
	case identifyPushSupported:
		return "supported"
	case identifyPushUnsupported:
		return "not supported"
	default:
		return "unknown"
	}
}