package oracle

import (
	"strings"
	"sync"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

var (
	metricsOnce sync.Once

	rpcRequestsTotal *prometheus.CounterVec
	rpcLatency       *prometheus.HistogramVec
)

func initMetrics() {
	metricsOnce.Do(func() {
		rpcRequestsTotal = promauto.NewCounterVec(
			prometheus.CounterOpts{
				Namespace: "fx",
				Subsystem: "oracle",
				Name:      "requests_total",
				Help:      "Total number of FX oracle RPC calls handled.",
			},
			[]string{"method", "result"},
		)

		rpcLatency = promauto.NewHistogramVec(
			prometheus.HistogramOpts{
				Namespace: "fx",
				Subsystem: "oracle",
				Name:      "request_latency_seconds",
				Help:      "Latency of FX oracle RPC calls.",
				Buckets:   prometheus.DefBuckets,
			},
			[]string{"method", "result"},
		)
	})
}

func observeRPC(start time.Time, method string, err error) {
	result := labelFromError(err)
	rpcRequestsTotal.WithLabelValues(method, result).Inc()
	rpcLatency.WithLabelValues(method, result).Observe(time.Since(start).Seconds())
}

func labelFromError(err error) string {
	if err == nil {
		return strings.ToLower(codes.OK.String())
	}
	st, ok := status.FromError(err)
	if !ok {
		return "error"
	}
	code := st.Code()
	if code == codes.OK {
		return strings.ToLower(code.String())
	}
	return strings.ToLower(code.String())
}
