package metrics

import (
	"net/http"
	"strconv"
	"time"

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

// MetricsService interface defines the contract for metrics operations
type MetricsService interface {
	RecordHTTPRequest(method, path string, statusCode int, duration time.Duration)
	RecordDBOperation(operation, table string)
	RecordAuthAttempt(action, result string)
	StartMetricsServer(port string)
	MetricsMiddleware() gin.HandlerFunc
}

// PrometheusMetricsService implements MetricsService using Prometheus
type PrometheusMetricsService struct {
	httpRequestsTotal   *prometheus.CounterVec
	httpRequestDuration *prometheus.HistogramVec
	dbOperationsTotal   *prometheus.CounterVec
	authAttemptsTotal   *prometheus.CounterVec
}

// NewPrometheusMetricsService creates a new Prometheus metrics service
func NewPrometheusMetricsService() MetricsService {
	return &PrometheusMetricsService{
		httpRequestsTotal: promauto.NewCounterVec(
			prometheus.CounterOpts{
				Name: "http_requests_total",
				Help: "Total number of HTTP requests",
			},
			[]string{"method", "path", "status"},
		),
		httpRequestDuration: promauto.NewHistogramVec(
			prometheus.HistogramOpts{
				Name:    "http_request_duration_seconds",
				Help:    "HTTP request duration in seconds",
				Buckets: prometheus.DefBuckets,
			},
			[]string{"method", "path"},
		),
		dbOperationsTotal: promauto.NewCounterVec(
			prometheus.CounterOpts{
				Name: "db_operations_total",
				Help: "Total number of database operations",
			},
			[]string{"operation", "table"},
		),
		authAttemptsTotal: promauto.NewCounterVec(
			prometheus.CounterOpts{
				Name: "auth_attempts_total",
				Help: "Total number of authentication attempts",
			},
			[]string{"action", "result"},
		),
	}
}

// RecordHTTPRequest records an HTTP request
func (m *PrometheusMetricsService) RecordHTTPRequest(method, path string, statusCode int, duration time.Duration) {
	status := strconv.Itoa(statusCode)
	m.httpRequestsTotal.WithLabelValues(method, path, status).Inc()
	m.httpRequestDuration.WithLabelValues(method, path).Observe(duration.Seconds())
}

// RecordDBOperation records a database operation
func (m *PrometheusMetricsService) RecordDBOperation(operation, table string) {
	m.dbOperationsTotal.WithLabelValues(operation, table).Inc()
}

// RecordAuthAttempt records an authentication attempt
func (m *PrometheusMetricsService) RecordAuthAttempt(action, result string) {
	m.authAttemptsTotal.WithLabelValues(action, result).Inc()
}

// StartMetricsServer starts the Prometheus metrics server
func (m *PrometheusMetricsService) StartMetricsServer(port string) {
	http.Handle("/metrics", promhttp.Handler())
	go func() {
		if err := http.ListenAndServe(":"+port, nil); err != nil {
			// Log error but don't fail the application
		}
	}()
}

// MetricsMiddleware creates a Gin middleware for HTTP metrics
func (m *PrometheusMetricsService) MetricsMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()

		c.Next()

		duration := time.Since(start)
		m.RecordHTTPRequest(c.Request.Method, c.FullPath(), c.Writer.Status(), duration)
	}
}
