package grpc

import (
	"git.frostfs.info/TrueCloudLab/frostfs-observability/metrics"
	grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
	"github.com/prometheus/client_golang/prometheus"
	dto "github.com/prometheus/client_model/go"
	"google.golang.org/grpc"
)

var clientMetrics = grpcprom.NewClientMetrics(
	grpcprom.WithClientHandlingTimeHistogram(
		grpcprom.WithHistogramBuckets(prometheus.DefBuckets),
	),
	grpcprom.WithClientStreamRecvHistogram(
		grpcprom.WithHistogramBuckets(prometheus.DefBuckets),
	),
)

func init() {
	// Description copied from repository of grpc-ecosystem
	// https://github.com/grpc-ecosystem/go-grpc-middleware/blob/71d7422112b1d7fadd4b8bf12a6f33ba6d22e98e/providers/prometheus/client_metrics.go#L31
	descs := []metrics.Description{
		{
			Name:           "grpc_client_started_total",
			Type:           dto.MetricType_COUNTER.String(),
			Help:           "Total number of RPCs started on the client.",
			VariableLabels: []string{"grpc_type", "grpc_service", "grpc_method"},
		},
		{
			Name:           "grpc_client_handled_total",
			Type:           dto.MetricType_COUNTER.String(),
			Help:           "Total number of RPCs completed by the client, regardless of success or failure.",
			VariableLabels: []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"},
		},
		{
			Name:           "grpc_client_msg_received_total",
			Type:           dto.MetricType_COUNTER.String(),
			Help:           "Total number of RPC stream messages received by the client.",
			VariableLabels: []string{"grpc_type", "grpc_service", "grpc_method"},
		},
		{
			Name:           "grpc_client_msg_sent_total",
			Type:           dto.MetricType_COUNTER.String(),
			Help:           "Total number of gRPC stream messages sent by the client.",
			VariableLabels: []string{"grpc_type", "grpc_service", "grpc_method"},
		},
		{
			Name:           "grpc_client_handling_seconds",
			Type:           dto.MetricType_HISTOGRAM.String(),
			Help:           "Histogram of response latency (seconds) of the gRPC until it is finished by the application.",
			VariableLabels: []string{"grpc_type", "grpc_service", "grpc_method"},
		},
		{
			Name:           "grpc_client_msg_recv_handling_seconds",
			Type:           dto.MetricType_HISTOGRAM.String(),
			Help:           "Histogram of response latency (seconds) of the gRPC single message receive.",
			VariableLabels: []string{"grpc_type", "grpc_service", "grpc_method"},
		},
	}
	metrics.MustRegister(clientMetrics, descs...)
}

// NewUnaryClientInterceptor returns client interceptor to collect metrics from unary RPCs.
func NewUnaryClientInterceptor() grpc.UnaryClientInterceptor {
	return clientMetrics.UnaryClientInterceptor()
}

// NewStreamClientInterceptor returns client interceptor to collect metrics from stream RPCs.
func NewStreamClientInterceptor() grpc.StreamClientInterceptor {
	return clientMetrics.StreamClientInterceptor()
}