//! Prometheus Metrics for ML Model Performance Monitoring
//!
//! This module defines Prometheus metrics for observing ML model health,
//! performance, and fallback behavior in production.

#![allow(clippy::expect_used)] // Metric registration failures are fatal

use once_cell::sync::Lazy;
use prometheus::{
    register_counter_vec, register_gauge_vec, register_histogram_vec, CounterVec, GaugeVec,
    HistogramVec,
};

/// Histogram for ML model inference latency in microseconds
///
/// Labels: model_id
pub static ML_INFERENCE_LATENCY_US: Lazy<HistogramVec> = Lazy::new(|| {
    register_histogram_vec!(
        "ml_inference_latency_microseconds",
        "ML model inference latency in microseconds",
        &["model_id"],
        vec![10.0, 50.0, 100.0, 500.0, 1000.0, 5000.0, 10000.0]
    )
    .expect("Failed to register ml_inference_latency_microseconds histogram")
});

/// Gauge for ML model accuracy percentage (0-100)
///
/// Labels: model_id
pub static ML_MODEL_ACCURACY: Lazy<GaugeVec> = Lazy::new(|| {
    register_gauge_vec!(
        "ml_model_accuracy_percent",
        "ML model prediction accuracy percentage",
        &["model_id"]
    )
    .expect("Failed to register ml_model_accuracy_percent gauge")
});

/// Gauge for ML model health status
///
/// Values: 0=Healthy, 1=Degraded, 2=Unhealthy, 3=Failed, 4=Offline
///
/// Labels: model_id
pub static ML_MODEL_HEALTH: Lazy<GaugeVec> = Lazy::new(|| {
    register_gauge_vec!(
        "ml_model_health_status",
        "ML model health status (0=Healthy, 1=Degraded, 2=Unhealthy, 3=Failed, 4=Offline)",
        &["model_id"]
    )
    .expect("Failed to register ml_model_health_status gauge")
});

/// Counter for ML fallback triggers
///
/// Labels: from_model, to_model, reason
pub static ML_FALLBACK_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    register_counter_vec!(
        "ml_fallback_total",
        "Total number of ML model fallback events",
        &["from_model", "to_model", "reason"]
    )
    .expect("Failed to register ml_fallback_total counter")
});

/// Counter for ML predictions by type
///
/// Labels: model_id, prediction_type (buy/sell/hold)
pub static ML_PREDICTIONS_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    register_counter_vec!(
        "ml_predictions_total",
        "Total number of ML predictions by type",
        &["model_id", "prediction_type"]
    )
    .expect("Failed to register ml_predictions_total counter")
});

/// Counter for ML prediction errors
///
/// Labels: model_id, error_type
pub static ML_PREDICTION_ERRORS_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    register_counter_vec!(
        "ml_prediction_errors_total",
        "Total number of ML prediction errors",
        &["model_id", "error_type"]
    )
    .expect("Failed to register ml_prediction_errors_total counter")
});

/// Counter for ML performance alerts by type and severity
///
/// Labels: model_id, alert_type, severity
pub static ML_ALERTS_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    register_counter_vec!(
        "ml_alerts_total",
        "Total number of ML performance alerts",
        &["model_id", "alert_type", "severity"]
    )
    .expect("Failed to register ml_alerts_total counter")
});

/// Gauge for ML model drift score
///
/// Labels: model_id
pub static ML_MODEL_DRIFT_SCORE: Lazy<GaugeVec> = Lazy::new(|| {
    register_gauge_vec!(
        "ml_model_drift_score",
        "ML model drift detection score (percentage change)",
        &["model_id"]
    )
    .expect("Failed to register ml_model_drift_score gauge")
});

/// Gauge for ML model confidence score
///
/// Labels: model_id
pub static ML_MODEL_CONFIDENCE: Lazy<GaugeVec> = Lazy::new(|| {
    register_gauge_vec!(
        "ml_model_confidence_score",
        "ML model prediction confidence score (0-1)",
        &["model_id"]
    )
    .expect("Failed to register ml_model_confidence_score gauge")
});

/// Gauge for ML model memory usage in MB
///
/// Labels: model_id
pub static ML_MODEL_MEMORY_MB: Lazy<GaugeVec> = Lazy::new(|| {
    register_gauge_vec!(
        "ml_model_memory_megabytes",
        "ML model memory usage in megabytes",
        &["model_id"]
    )
    .expect("Failed to register ml_model_memory_megabytes gauge")
});

/// Gauge for ML model CPU utilization percentage
///
/// Labels: model_id
pub static ML_MODEL_CPU_PERCENT: Lazy<GaugeVec> = Lazy::new(|| {
    register_gauge_vec!(
        "ml_model_cpu_utilization_percent",
        "ML model CPU utilization percentage",
        &["model_id"]
    )
    .expect("Failed to register ml_model_cpu_utilization_percent gauge")
});

/// Counter for circuit breaker state changes
///
/// Labels: model_id, from_state, to_state
pub static ML_CIRCUIT_BREAKER_TRANSITIONS: Lazy<CounterVec> = Lazy::new(|| {
    register_counter_vec!(
        "ml_circuit_breaker_transitions_total",
        "Total number of circuit breaker state transitions",
        &["model_id", "from_state", "to_state"]
    )
    .expect("Failed to register ml_circuit_breaker_transitions_total counter")
});

/// Helper function to map model health to numeric value for Prometheus
pub fn health_to_metric_value(health: &crate::services::ml_fallback_manager::ModelHealth) -> f64 {
    match health {
        crate::services::ml_fallback_manager::ModelHealth::Healthy => 0.0,
        crate::services::ml_fallback_manager::ModelHealth::Degraded => 1.0,
        crate::services::ml_fallback_manager::ModelHealth::Unhealthy => 2.0,
        crate::services::ml_fallback_manager::ModelHealth::Failed => 3.0,
        crate::services::ml_fallback_manager::ModelHealth::Offline => 4.0,
    }
}

/// Helper function to get alert severity as string
pub fn alert_severity_str(
    severity: &crate::services::ml_performance_monitor::AlertSeverity,
) -> &'static str {
    match severity {
        crate::services::ml_performance_monitor::AlertSeverity::Info => "info",
        crate::services::ml_performance_monitor::AlertSeverity::Warning => "warning",
        crate::services::ml_performance_monitor::AlertSeverity::Critical => "critical",
        crate::services::ml_performance_monitor::AlertSeverity::Emergency => "emergency",
    }
}

/// Helper function to get alert type as string
pub fn alert_type_str(
    alert_type: &crate::services::ml_performance_monitor::AlertType,
) -> &'static str {
    match alert_type {
        crate::services::ml_performance_monitor::AlertType::HighLatency => "high_latency",
        crate::services::ml_performance_monitor::AlertType::LowAccuracy => "low_accuracy",
        crate::services::ml_performance_monitor::AlertType::HighMemoryUsage => "high_memory",
        crate::services::ml_performance_monitor::AlertType::ModelDrift => "model_drift",
        crate::services::ml_performance_monitor::AlertType::ModelFailure => "model_failure",
        crate::services::ml_performance_monitor::AlertType::PredictionAnomaly => {
            "prediction_anomaly"
        },
    }
}
