package metrics

import (
	"context"
	"net/url"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"k8s.io/client-go/tools/metrics"
)

func init() {
	// client-go only provides an interface, so we need to implements it with prometheus
	// ref: https://github.com/kubernetes/client-go/blob/v0.22.1/tools/metrics/metrics.go
	metrics.Register(metrics.RegisterOpts{
		RequestLatency:     &KubeLatencyMetric{latencySeconds: KubeRequestLatency},
		RateLimiterLatency: &KubeLatencyMetric{latencySeconds: KubeRateLimiterLatency},
	})
}

type KubeLatencyMetric struct {
	latencySeconds *prometheus.HistogramVec
}

func (k *KubeLatencyMetric) Observe(_ context.Context, verb string, u url.URL, latency time.Duration) {
	k.latencySeconds.WithLabelValues(u.Path, verb).Observe(latency.Seconds())
}

var (
	KubeRequestLatency = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "kube_request_latency_seconds",
			Buckets: prometheus.ExponentialBuckets(0.005, 2, 13),
		}, []string{"path", "method"})

	KubeRateLimiterLatency = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "kube_request_ratelimit_seconds",
			Buckets: prometheus.ExponentialBuckets(0.005, 2, 13),
		}, []string{"path", "method"})

	RequestDuration = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "request_duration_seconds",
			Buckets: prometheus.ExponentialBuckets(0.005, 2, 14),
		}, []string{"path", "method"})

	RequestCounter = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "request_count",
		}, []string{"path", "method"})

	ResponseCounter = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "response_count",
		}, []string{"path", "method", "status"})

	LivingTestbeds = promauto.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "living_testbed",
		}, []string{"testbed", "namespace"})
)

func NewTestbed(name string) {
	LivingTestbeds.With(map[string]string{"testbed": name, "namespace": name}).Set(1)
}

func DelTestbed(name string) {
	LivingTestbeds.Delete(map[string]string{"testbed": name, "namespace": name})
}
