package observability

import (
	"github.com/prometheus/client_golang/prometheus"
)

const (
	namespace = "serviceproxy"
)

// Metrics holds all Prometheus metrics.
type Metrics struct {
	requestsTotal      *prometheus.CounterVec
	requestDuration    *prometheus.HistogramVec
	backendErrorsTotal *prometheus.CounterVec
	tlsCertExpiry      *prometheus.GaugeVec
}

// NewMetrics creates and registers all metrics with the default registry.
func NewMetrics() *Metrics {
	return NewMetricsWithRegistry(prometheus.DefaultRegisterer)
}

// NewMetricsWithRegistry creates metrics with a custom registry.
func NewMetricsWithRegistry(reg prometheus.Registerer) *Metrics {
	m := &Metrics{
		requestsTotal: prometheus.NewCounterVec(
			prometheus.CounterOpts{
				Namespace: namespace,
				Name:      "requests_total",
				Help:      "Total number of requests",
			},
			[]string{"method", "route", "status"},
		),
		requestDuration: prometheus.NewHistogramVec(
			prometheus.HistogramOpts{
				Namespace: namespace,
				Name:      "request_duration_seconds",
				Help:      "Request latency distribution",
				Buckets:   prometheus.DefBuckets,
			},
			[]string{"method", "route"},
		),
		backendErrorsTotal: prometheus.NewCounterVec(
			prometheus.CounterOpts{
				Namespace: namespace,
				Name:      "backend_errors_total",
				Help:      "Total number of backend errors",
			},
			[]string{"route", "error_type"},
		),
		tlsCertExpiry: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "tls_cert_expiry_seconds",
				Help:      "TLS certificate expiry timestamp",
			},
			[]string{"namespace", "secret"},
		),
	}

	// Register metrics
	reg.MustRegister(
		m.requestsTotal,
		m.requestDuration,
		m.backendErrorsTotal,
		m.tlsCertExpiry,
	)

	return m
}

// RecordRequest records a request.
func (m *Metrics) RecordRequest(method, route string, status int) {
	m.requestsTotal.WithLabelValues(method, route, statusToString(status)).Inc()
}

// RecordLatency records request latency.
func (m *Metrics) RecordLatency(method, route string, duration float64) {
	m.requestDuration.WithLabelValues(method, route).Observe(duration)
}

// RecordBackendError records a backend error.
func (m *Metrics) RecordBackendError(route, errorType string) {
	m.backendErrorsTotal.WithLabelValues(route, errorType).Inc()
}

// SetTLSCertExpiry sets the TLS certificate expiry timestamp.
func (m *Metrics) SetTLSCertExpiry(namespace, secret string, expiry float64) {
	m.tlsCertExpiry.WithLabelValues(namespace, secret).Set(expiry)
}

func statusToString(status int) string {
	switch {
	case status >= 200 && status < 300:
		return "2xx"
	case status >= 300 && status < 400:
		return "3xx"
	case status >= 400 && status < 500:
		return "4xx"
	case status >= 500:
		return "5xx"
	default:
		return "unknown"
	}
}
