package monitoring

import (
	"time"

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

// Métriques Prometheus custom pour l'application Veza

var (
	// HTTP Requests Metrics
	HTTPRequestsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_http_requests_total",
			Help: "Total number of HTTP requests",
		},
		[]string{"method", "endpoint", "status"},
	)

	HTTPRequestDuration = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "veza_http_request_duration_seconds",
			Help:    "HTTP request duration in seconds",
			Buckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0},
		},
		[]string{"method", "endpoint"},
	)

	// Authentication Metrics
	AuthLoginAttempts = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_auth_login_attempts_total",
			Help: "Total number of login attempts",
		},
		[]string{"success"},
	)

	AuthSessionActive = promauto.NewGauge(
		prometheus.GaugeOpts{
			Name: "veza_auth_sessions_active",
			Help: "Number of active sessions",
		},
	)

	// Database Metrics
	DatabaseQueryDuration = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "veza_database_query_duration_seconds",
			Help:    "Database query duration in seconds",
			Buckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0},
		},
		[]string{"operation", "table"},
	)

	DatabaseConnectionsActive = promauto.NewGauge(
		prometheus.GaugeOpts{
			Name: "veza_database_connections_active",
			Help: "Number of active database connections",
		},
	)

	DatabaseQueryErrors = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_database_query_errors_total",
			Help: "Total number of database query errors",
		},
		[]string{"operation", "error_type"},
	)

	// File Upload Metrics
	FileUploadsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_file_uploads_total",
			Help: "Total number of file uploads",
		},
		[]string{"type", "status"},
	)

	FileUploadSize = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "veza_file_upload_size_bytes",
			Help:    "File upload size in bytes",
			Buckets: prometheus.ExponentialBuckets(1024, 2, 15), // 1KB to 32MB
		},
		[]string{"type"},
	)

	// Rate Limiting Metrics
	RateLimitHitsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_rate_limit_hits_total",
			Help: "Total number of rate limit hits",
		},
		[]string{"endpoint", "limit_type"},
	)

	// Active Users Metrics
	ActiveUsers = promauto.NewGauge(
		prometheus.GaugeOpts{
			Name: "veza_active_users",
			Help: "Number of active users",
		},
	)

	// WebSocket Metrics
	WebSocketConnectionsActive = promauto.NewGauge(
		prometheus.GaugeOpts{
			Name: "veza_websocket_connections_active",
			Help: "Number of active WebSocket connections",
		},
	)

	WebSocketMessagesTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_websocket_messages_total",
			Help: "Total number of WebSocket messages",
		},
		[]string{"type", "status"},
	)

	// Cache Metrics
	CacheHitsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_cache_hits_total",
			Help: "Total number of cache hits",
		},
		[]string{"cache_type"},
	)

	CacheMissesTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_cache_misses_total",
			Help: "Total number of cache misses",
		},
		[]string{"cache_type"},
	)

	// Error Metrics
	ErrorsTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_errors_total",
			Help: "Total number of errors",
		},
		[]string{"type", "severity"},
	)

	// Health Check Metrics
	HealthCheckDuration = promauto.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "veza_health_check_duration_ms",
			Help:    "Health check duration in milliseconds",
			Buckets: []float64{1, 5, 10, 25, 50, 100, 250, 500, 1000},
		},
		[]string{"service"}, // database, redis, chat_server, stream_server
	)

	HealthCheckStatus = promauto.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "veza_health_check_status",
			Help: "Health check status (1=ok, 0.5=slow, 0=error)",
		},
		[]string{"service"},
	)

	// MOD-P2-003: Business Metrics
	TracksUploadedTotal = promauto.NewCounter(
		prometheus.CounterOpts{
			Name: "veza_tracks_uploaded_total",
			Help: "Total number of tracks uploaded",
		},
	)

	UsersRegisteredTotal = promauto.NewCounter(
		prometheus.CounterOpts{
			Name: "veza_users_registered_total",
			Help: "Total number of users registered",
		},
	)

	PlaylistsCreatedTotal = promauto.NewCounter(
		prometheus.CounterOpts{
			Name: "veza_playlists_created_total",
			Help: "Total number of playlists created",
		},
	)

	UploadsFailedTotal = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "veza_uploads_failed_total",
			Help: "Total number of failed uploads",
		},
		[]string{"reason"}, // ClamAV, validation, quota, etc.
	)
)

// Middleware pour enregistrer les métriques HTTP
func HTTPMetricsMiddleware(endpoint string, duration time.Duration, statusCode int, method string) {
	status := string(rune(statusCode / 100)) // '2', '4', '5'

	HTTPRequestsTotal.WithLabelValues(method, endpoint, status).Inc()
	HTTPRequestDuration.WithLabelValues(method, endpoint).Observe(duration.Seconds())
}

// Enregistrer une tentative de login
func RecordLoginAttempt(success bool) {
	status := "failure"
	if success {
		status = "success"
	}
	AuthLoginAttempts.WithLabelValues(status).Inc()
}

// Mettre à jour le nombre de sessions actives
func UpdateActiveSessions(count int) {
	AuthSessionActive.Set(float64(count))
}

// Enregistrer une requête database
func RecordDatabaseQuery(operation, table string, duration time.Duration) {
	DatabaseQueryDuration.WithLabelValues(operation, table).Observe(duration.Seconds())
}

// Enregistrer une erreur de database
func RecordDatabaseError(operation, errorType string) {
	DatabaseQueryErrors.WithLabelValues(operation, errorType).Inc()
}

// Enregistrer un upload de fichier
func RecordFileUpload(fileType, status string, sizeBytes int64) {
	FileUploadsTotal.WithLabelValues(fileType, status).Inc()
	FileUploadSize.WithLabelValues(fileType).Observe(float64(sizeBytes))
}

// Enregistrer un hit de rate limit
func RecordRateLimitHit(endpoint, limitType string) {
	RateLimitHitsTotal.WithLabelValues(endpoint, limitType).Inc()
}

// Mettre à jour le nombre d'utilisateurs actifs
func UpdateActiveUsers(count int) {
	ActiveUsers.Set(float64(count))
}

// Enregistrer une connexion WebSocket
func UpdateWebSocketConnections(count int) {
	WebSocketConnectionsActive.Set(float64(count))
}

// Enregistrer un message WebSocket
func RecordWebSocketMessage(messageType, status string) {
	WebSocketMessagesTotal.WithLabelValues(messageType, status).Inc()
}

// Enregistrer un cache hit
func RecordCacheHit(cacheType string) {
	CacheHitsTotal.WithLabelValues(cacheType).Inc()
}

// Enregistrer un cache miss
func RecordCacheMiss(cacheType string) {
	CacheMissesTotal.WithLabelValues(cacheType).Inc()
}

// Enregistrer une erreur
func RecordError(errorType, severity string) {
	ErrorsTotal.WithLabelValues(errorType, severity).Inc()
}

// Enregistrer un health check
func RecordHealthCheck(service string, durationMs float64, status string) {
	HealthCheckDuration.WithLabelValues(service).Observe(durationMs)

	// Convertir le status en valeur numérique pour la gauge
	var statusValue float64
	switch status {
	case "ok":
		statusValue = 1.0
	case "slow":
		statusValue = 0.5
	case "error":
		statusValue = 0.0
	default:
		statusValue = 0.0
	}
	HealthCheckStatus.WithLabelValues(service).Set(statusValue)
}

// MOD-P2-003: Business Metrics Functions

// RecordTrackUploaded incrémente le compteur de tracks uploadés
func RecordTrackUploaded() {
	TracksUploadedTotal.Inc()
}

// RecordUserRegistered incrémente le compteur d'utilisateurs enregistrés
func RecordUserRegistered() {
	UsersRegisteredTotal.Inc()
}

// RecordPlaylistCreated incrémente le compteur de playlists créées
func RecordPlaylistCreated() {
	PlaylistsCreatedTotal.Inc()
}

// RecordUploadFailed enregistre un échec d'upload avec la raison
func RecordUploadFailed(reason string) {
	UploadsFailedTotal.WithLabelValues(reason).Inc()
}
