package observability

import (
	"net/http"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// Metrics contains the Prometheus metrics for the application.
type Metrics struct {
	RequestsTotal    *prometheus.CounterVec
	RequestDuration  *prometheus.HistogramVec
	DBQueriesTotal   *prometheus.CounterVec
	DBQueryDuration  *prometheus.HistogramVec
}

// NewMetrics creates and registers the Prometheus metrics.
func NewMetrics(reg prometheus.Registerer) *Metrics {
	return &Metrics{
		RequestsTotal: promauto.With(reg).NewCounterVec(
			prometheus.CounterOpts{
				Name: "http_requests_total",
				Help: "Total number of HTTP requests.",
			},
			[]string{"method", "path", "status"},
		),
		RequestDuration: promauto.With(reg).NewHistogramVec(
			prometheus.HistogramOpts{
				Name:    "http_request_duration_seconds",
				Help:    "Duration of HTTP requests.",
				Buckets: prometheus.DefBuckets,
			},
			[]string{"method", "path"},
		),
		DBQueriesTotal: promauto.With(reg).NewCounterVec(
			prometheus.CounterOpts{
				Name: "db_queries_total",
				Help: "Total number of database queries.",
			},
			[]string{"operation", "status"},
		),
		DBQueryDuration: promauto.With(reg).NewHistogramVec(
			prometheus.HistogramOpts{
				Name:    "db_query_duration_seconds",
				Help:    "Duration of database queries.",
				Buckets: prometheus.DefBuckets,
			},
			[]string{"operation", "status"},
		),
	}
}

// PrometheusMiddleware returns an HTTP middleware that records Prometheus metrics.
func (m *Metrics) PrometheusMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		rw := &responseWriter{ResponseWriter: w}
		next.ServeHTTP(rw, r)

		duration := time.Since(start).Seconds()
		m.RequestDuration.WithLabelValues(r.Method, r.URL.Path).Observe(duration)
		m.RequestsTotal.WithLabelValues(r.Method, r.URL.Path, http.StatusText(rw.statusCode)).Inc()
	})
}

// PrometheusHandler returns an HTTP handler for serving Prometheus metrics.
func PrometheusHandler(reg prometheus.Gatherer) http.Handler {
	return promhttp.HandlerFor(reg, promhttp.HandlerOpts{})
}
