package metrics

import (
	"strconv"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"veza-backend-api/internal/errors"
)

var (
	// errorsTotal compte le total d'erreurs par code d'erreur et status HTTP
	errorsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_errors_legacy_total",
			Help: "Total number of errors by code and HTTP status",
		},
		[]string{"error_code", "http_status"},
	)

	// errorsByCode compte les erreurs par code d'erreur
	errorsByCode = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_errors_by_code_total",
			Help: "Total number of errors by error code",
		},
		[]string{"error_code"},
	)

	// errorsByHTTPStatus compte les erreurs par status HTTP
	errorsByHTTPStatus = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_errors_by_http_status_total",
			Help: "Total number of errors by HTTP status code",
		},
		[]string{"http_status"},
	)

	// dbQueriesTotal compte le total de requêtes DB par opération et table
	dbQueriesTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_db_queries_total",
			Help: "Total number of database queries",
		},
		[]string{"operation", "table"},
	)

	// dbQueryDuration mesure la durée des requêtes DB
	dbQueryDuration = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "veza_db_query_duration_seconds",
			Help:    "Database query duration in seconds",
			Buckets: []float64{.001, .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5},
		},
		[]string{"operation", "table"},
	)

	// dbConnections mesure le nombre de connexions DB par état
	dbConnections = promauto.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "veza_db_connections",
			Help: "Number of database connections",
		},
		[]string{"state"}, // open, idle, in_use
	)

	// dbSlowQueries compte les requêtes lentes par opération et table
	// BE-DB-018: Slow query logging and performance metrics
	dbSlowQueries = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_db_slow_queries_total",
			Help: "Total number of slow database queries",
		},
		[]string{"operation", "table"},
	)

	// dbSlowQueryDuration mesure la durée des requêtes lentes
	dbSlowQueryDuration = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "veza_db_slow_query_duration_seconds",
			Help:    "Slow database query duration in seconds",
			Buckets: []float64{1, 2, 5, 10, 30, 60, 120}, // Buckets for slow queries (seconds)
		},
		[]string{"operation", "table"},
	)
)

// RecordErrorPrometheus enregistre une erreur dans Prometheus
func RecordErrorPrometheus(code errors.ErrorCode, httpStatus int) {
	codeStr := strconv.Itoa(int(code))
	statusStr := strconv.Itoa(httpStatus)

	errorsTotal.WithLabelValues(codeStr, statusStr).Inc()
	errorsByCode.WithLabelValues(codeStr).Inc()
	errorsByHTTPStatus.WithLabelValues(statusStr).Inc()
}

// RecordDBQuery enregistre une requête DB dans Prometheus
// operation: type d'opération (SELECT, INSERT, UPDATE, DELETE, etc.)
// table: nom de la table (ou "unknown" si non disponible)
// duration: durée de la requête
func RecordDBQuery(operation, table string, duration time.Duration) {
	dbQueriesTotal.WithLabelValues(operation, table).Inc()
	dbQueryDuration.WithLabelValues(operation, table).Observe(duration.Seconds())
}

// UpdateDBConnections met à jour les métriques de connexions DB
// open: nombre total de connexions ouvertes
// idle: nombre de connexions inactives
// inUse: nombre de connexions en cours d'utilisation
func UpdateDBConnections(open, idle, inUse int) {
	dbConnections.WithLabelValues("open").Set(float64(open))
	dbConnections.WithLabelValues("idle").Set(float64(idle))
	dbConnections.WithLabelValues("in_use").Set(float64(inUse))
}

// RecordSlowQuery enregistre une requête lente dans Prometheus
// BE-DB-018: Slow query logging and performance metrics
// operation: type d'opération (SELECT, INSERT, UPDATE, DELETE, etc.)
// table: nom de la table (ou "unknown" si non disponible)
// duration: durée de la requête
func RecordSlowQuery(operation, table string, duration time.Duration) {
	dbSlowQueries.WithLabelValues(operation, table).Inc()
	dbSlowQueryDuration.WithLabelValues(operation, table).Observe(duration.Seconds())
}
