// Package metrics provides Prometheus metrics collection and instrumentation.
package metrics

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// Metrics holds all Prometheus metrics.
type Metrics struct {
	httpRequestDuration *prometheus.HistogramVec
	httpRequestTotal    *prometheus.CounterVec
	httpErrorsTotal     *prometheus.CounterVec
	registry            *prometheus.Registry
}

// NewMetrics creates a new metrics registry with all metrics.
func NewMetrics() *Metrics {
	registry := prometheus.NewRegistry()

	m := &Metrics{
		registry: registry,
		httpRequestDuration: prometheus.NewHistogramVec(
			prometheus.HistogramOpts{
				Name:    "http_request_duration_seconds",
				Help:    "HTTP request duration in seconds",
				Buckets: prometheus.DefBuckets,
			},
			[]string{"method", "path", "status"},
		),
		httpRequestTotal: prometheus.NewCounterVec(
			prometheus.CounterOpts{
				Name: "http_requests_total",
				Help: "Total number of HTTP requests",
			},
			[]string{"method", "path", "status"},
		),
		httpErrorsTotal: prometheus.NewCounterVec(
			prometheus.CounterOpts{
				Name: "http_errors_total",
				Help: "Total number of HTTP errors",
			},
			[]string{"method", "path", "status"},
		),
	}

	// Register all metrics
	registry.MustRegister(m.httpRequestDuration)
	registry.MustRegister(m.httpRequestTotal)
	registry.MustRegister(m.httpErrorsTotal)

	return m
}

// HTTPMiddleware returns a Gin middleware for collecting HTTP metrics.
func (m *Metrics) HTTPMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()

		// Process request
		c.Next()

		// Calculate duration
		duration := time.Since(start).Seconds()

		// Get request details
		method := c.Request.Method
		path := c.FullPath()
		if path == "" {
			path = c.Request.URL.Path
		}
		status := c.Writer.Status()

		// Record metrics
		m.httpRequestDuration.WithLabelValues(method, path, http.StatusText(status)).Observe(duration)
		m.httpRequestTotal.WithLabelValues(method, path, http.StatusText(status)).Inc()

		// Record errors (4xx and 5xx)
		if status >= 400 {
			m.httpErrorsTotal.WithLabelValues(method, path, http.StatusText(status)).Inc()
		}
	}
}

// Handler returns an HTTP handler for the /metrics endpoint.
func (m *Metrics) Handler() http.Handler {
	return promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{})
}

// Registry returns the Prometheus registry.
func (m *Metrics) Registry() *prometheus.Registry {
	return m.registry
}
