//! Prometheus metrics for streaming channels

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

use once_cell::sync::Lazy;
use prometheus::{CounterVec, GaugeVec, Opts};

/// Stream buffer utilization (0-100%)
pub static STREAM_BUFFER_UTILIZATION: Lazy<GaugeVec> = Lazy::new(|| {
    GaugeVec::new(
        Opts::new(
            "stream_buffer_utilization_percent",
            "Current buffer utilization percentage for streaming channels",
        ),
        &["stream_name"],
    )
    .expect("Failed to create stream_buffer_utilization_percent metric")
});

/// Total messages sent through streams
pub static STREAM_MESSAGES_SENT_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    CounterVec::new(
        Opts::new(
            "stream_messages_sent_total",
            "Total number of messages sent through streaming channels",
        ),
        &["stream_name"],
    )
    .expect("Failed to create stream_messages_sent_total metric")
});

/// Total messages dropped due to backpressure
pub static STREAM_MESSAGES_DROPPED_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    CounterVec::new(
        Opts::new(
            "stream_messages_dropped_total",
            "Total number of messages dropped due to backpressure or timeouts",
        ),
        &["stream_name", "reason"],
    )
    .expect("Failed to create stream_messages_dropped_total metric")
});

/// Total send timeout events
pub static STREAM_SEND_TIMEOUTS_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    CounterVec::new(
        Opts::new(
            "stream_send_timeouts_total",
            "Total number of send timeout events in streaming channels",
        ),
        &["stream_name"],
    )
    .expect("Failed to create stream_send_timeouts_total metric")
});

/// Total backpressure warning events
pub static STREAM_BACKPRESSURE_WARNINGS_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    CounterVec::new(
        Opts::new(
            "stream_backpressure_warnings_total",
            "Total number of backpressure warning events (>80% utilization)",
        ),
        &["stream_name"],
    )
    .expect("Failed to create stream_backpressure_warnings_total metric")
});

/// Total backpressure critical events
pub static STREAM_BACKPRESSURE_CRITICAL_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
    CounterVec::new(
        Opts::new(
            "stream_backpressure_critical_total",
            "Total number of backpressure critical events (>95% utilization)",
        ),
        &["stream_name"],
    )
    .expect("Failed to create stream_backpressure_critical_total metric")
});

/// Stream metrics collector for easy instrumentation
pub struct StreamMetrics {
    stream_name: String,
}

impl StreamMetrics {
    /// Create a new stream metrics collector
    pub fn new(stream_name: impl Into<String>) -> Self {
        Self {
            stream_name: stream_name.into(),
        }
    }

    /// Update buffer utilization gauge
    #[inline]
    pub fn set_buffer_utilization(&self, utilization_pct: f64) {
        STREAM_BUFFER_UTILIZATION
            .with_label_values(&[&self.stream_name])
            .set(utilization_pct);
    }

    /// Increment messages sent counter
    #[inline]
    pub fn inc_messages_sent(&self) {
        STREAM_MESSAGES_SENT_TOTAL
            .with_label_values(&[&self.stream_name])
            .inc();
    }

    /// Increment messages dropped counter
    #[inline]
    pub fn inc_messages_dropped(&self, reason: &str) {
        STREAM_MESSAGES_DROPPED_TOTAL
            .with_label_values(&[self.stream_name.as_str(), reason])
            .inc();
    }

    /// Increment send timeouts counter
    #[inline]
    pub fn inc_send_timeouts(&self) {
        STREAM_SEND_TIMEOUTS_TOTAL
            .with_label_values(&[&self.stream_name])
            .inc();
    }

    /// Increment backpressure warnings counter
    #[inline]
    pub fn inc_backpressure_warnings(&self) {
        STREAM_BACKPRESSURE_WARNINGS_TOTAL
            .with_label_values(&[&self.stream_name])
            .inc();
    }

    /// Increment backpressure critical counter
    #[inline]
    pub fn inc_backpressure_critical(&self) {
        STREAM_BACKPRESSURE_CRITICAL_TOTAL
            .with_label_values(&[&self.stream_name])
            .inc();
    }

    /// Get the stream name
    pub fn stream_name(&self) -> &str {
        &self.stream_name
    }
}
