package gateway

import (
	"errors"
	"sync"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/tech/sendico/pkg/merrors"
)

var (
	metricsOnce sync.Once

	rpcLatency *prometheus.HistogramVec
	rpcStatus  *prometheus.CounterVec
)

func initMetrics() {
	metricsOnce.Do(func() {
		rpcLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{
			Namespace: "sendico",
			Subsystem: "chain_gateway",
			Name:      "rpc_latency_seconds",
			Help:      "Latency distribution for chain gateway RPC handlers.",
			Buckets:   prometheus.DefBuckets,
		}, []string{"method"})

		rpcStatus = promauto.NewCounterVec(prometheus.CounterOpts{
			Namespace: "sendico",
			Subsystem: "chain_gateway",
			Name:      "rpc_requests_total",
			Help:      "Total number of RPC invocations grouped by method and status.",
		}, []string{"method", "status"})
	})
}

func observeRPC(method string, err error, duration time.Duration) {
	if rpcLatency != nil {
		rpcLatency.WithLabelValues(method).Observe(duration.Seconds())
	}
	if rpcStatus != nil {
		rpcStatus.WithLabelValues(method, statusLabel(err)).Inc()
	}
}

func statusLabel(err error) string {
	switch {
	case err == nil:
		return "ok"
	case errors.Is(err, merrors.ErrInvalidArg):
		return "invalid_argument"
	case errors.Is(err, merrors.ErrNoData):
		return "not_found"
	case errors.Is(err, merrors.ErrDataConflict):
		return "conflict"
	case errors.Is(err, merrors.ErrAccessDenied):
		return "denied"
	case errors.Is(err, merrors.ErrInternal):
		return "internal"
	default:
		return "error"
	}
}
