//! Streaming Configuration and Types
//!
//! Provides centralized configuration for gRPC streaming endpoints with
//! performance optimizations based on message frequency patterns.
//!
//! Wave 67 Agent 3: HTTP/2 streaming performance optimizations

use std::time::Duration;

/// Stream type classification based on message frequency
///
/// Different stream types have different performance characteristics:
/// - **HighFrequency**: Market data, high-volume events (100K+ msg/s)
///
/// - **MediumFrequency**: Orders, positions, executions (10-100 msg/s)
/// - **LowFrequency**: Alerts, system status (1-10 msg/s)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamType {
    /// High-frequency streams (market data, tick data)
    ///
    /// Buffer size: 100,000 messages
    ///
    /// Use case: Market data feeds, high-volume event streams
    HighFrequency,

    /// Medium-frequency streams (orders, positions, executions)
    ///
    /// Buffer size: 10,000 messages
    ///
    /// Use case: Trading operations, position updates
    MediumFrequency,

    /// Low-frequency streams (alerts, monitoring, system status)
    ///
    /// Buffer size: 1,000 messages
    ///
    /// Use case: Administrative notifications, periodic updates
    LowFrequency,
}

impl StreamType {
    /// Get the optimal buffer size for this stream type
    ///
    /// Buffer sizes are tuned based on message frequency analysis:
    /// - High: 100K messages (market data can burst to 100K msg/s)
    ///
    /// - Medium: 10K messages (order flow typically 10-100 msg/s)
    /// - Low: 1K messages (alerts/status are infrequent)
    pub fn buffer_size(&self) -> usize {
        match self {
            StreamType::HighFrequency => 100_000,
            StreamType::MediumFrequency => 10_000,
            StreamType::LowFrequency => 1_000,
        }
    }

    /// Get the recommended keepalive interval for this stream type
    pub fn keepalive_interval(&self) -> Duration {
        match self {
            StreamType::HighFrequency => Duration::from_secs(10),
            StreamType::MediumFrequency => Duration::from_secs(30),
            StreamType::LowFrequency => Duration::from_secs(60),
        }
    }

    /// Get a description of this stream type
    pub fn description(&self) -> &'static str {
        match self {
            StreamType::HighFrequency => "High-frequency stream (100K+ msg/s)",
            StreamType::MediumFrequency => "Medium-frequency stream (10-100 msg/s)",
            StreamType::LowFrequency => "Low-frequency stream (1-10 msg/s)",
        }
    }
}

/// `HTTP`/2 configuration for gRPC streaming
///
/// These settings are optimized for HFT latency requirements:
/// - tcp_nodelay eliminates 40ms Nagle buffering delay
///
/// - Adaptive window sizing prevents flow control stalls
/// - Proper keepalive prevents connection churn
#[derive(Debug, Clone)]
pub struct StreamingConfig {
    /// Enable TCP_NODELAY to eliminate Nagle's algorithm delay (-40ms)
    pub tcp_nodelay: bool,

    /// `HTTP`/2 keepalive interval
    pub http2_keepalive_interval: Duration,

    /// `HTTP`/2 keepalive timeout
    pub http2_keepalive_timeout: Duration,

    /// Initial stream window size (per stream)
    pub initial_stream_window_size: u32,

    /// Initial connection window size (global)
    pub initial_connection_window_size: u32,

    /// Enable `HTTP`/2 adaptive window sizing
    pub http2_adaptive_window: bool,

    /// Maximum concurrent streams
    pub max_concurrent_streams: u32,

    /// Feature flag to enable/disable optimizations
    pub enable_http2_optimizations: bool,
}

impl Default for StreamingConfig {
    fn default() -> Self {
        Self {
            tcp_nodelay: true, // Critical: eliminates 40ms Nagle delay
            http2_keepalive_interval: Duration::from_secs(30),
            http2_keepalive_timeout: Duration::from_secs(10),
            initial_stream_window_size: 1024 * 1024, // 1MB per stream
            initial_connection_window_size: 10 * 1024 * 1024, // 10MB global
            http2_adaptive_window: true,
            max_concurrent_streams: 1000,
            enable_http2_optimizations: true, // Default enabled
        }
    }
}

impl StreamingConfig {
    /// Create configuration from environment variables
    pub fn from_env() -> Self {
        let mut config = Self::default();

        // Allow disabling optimizations via feature flag
        if let Ok(val) = std::env::var("ENABLE_HTTP2_OPTIMIZATIONS") {
            config.enable_http2_optimizations = val.parse().unwrap_or(true);
        }

        // Allow tuning individual parameters
        if let Ok(val) = std::env::var("HTTP2_STREAM_WINDOW_SIZE") {
            if let Ok(size) = val.parse() {
                config.initial_stream_window_size = size;
            }
        }

        if let Ok(val) = std::env::var("HTTP2_CONNECTION_WINDOW_SIZE") {
            if let Ok(size) = val.parse() {
                config.initial_connection_window_size = size;
            }
        }

        if let Ok(val) = std::env::var("HTTP2_MAX_CONCURRENT_STREAMS") {
            if let Ok(max) = val.parse() {
                config.max_concurrent_streams = max;
            }
        }

        config
    }

    /// Check if optimizations are enabled
    pub fn is_enabled(&self) -> bool {
        self.enable_http2_optimizations
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_stream_type_buffer_sizes() {
        assert_eq!(StreamType::HighFrequency.buffer_size(), 100_000);
        assert_eq!(StreamType::MediumFrequency.buffer_size(), 10_000);
        assert_eq!(StreamType::LowFrequency.buffer_size(), 1_000);
    }

    #[test]
    fn test_streaming_config_defaults() {
        let config = StreamingConfig::default();
        assert!(config.tcp_nodelay);
        assert!(config.http2_adaptive_window);
        assert!(config.enable_http2_optimizations);
        assert_eq!(config.max_concurrent_streams, 1000);
    }

    #[test]
    fn test_stream_type_descriptions() {
        assert!(!StreamType::HighFrequency.description().is_empty());
        assert!(!StreamType::MediumFrequency.description().is_empty());
        assert!(!StreamType::LowFrequency.description().is_empty());
    }
}
