//! Application state management with builder pattern

use std::sync::Arc;

/// Application state containing shared resources
///
/// This is a generic state type that can hold any database implementation.
/// Use the builder pattern to construct an AppState with optional features.
#[derive(Clone)]
pub struct AppState<DB: Send + Sync> {
    /// Database layer (generic over DB implementation)
    pub db: Arc<DB>,

    /// Optional metrics collector (if metrics feature is enabled)
    #[cfg(feature = "metrics")]
    pub metrics: Option<Arc<crate::metrics::MetricsCollector>>,

    /// Optional rate limiter (if rate-limit feature is enabled)
    #[cfg(feature = "rate-limit")]
    pub rate_limiter: Option<Arc<crate::rate_limit::RateLimiter>>,

    /// Optional authentication provider (if auth feature is enabled)
    #[cfg(feature = "auth")]
    pub auth: Option<Arc<crate::auth::AuthProvider>>,

    /// Optional event broadcaster (if websocket feature is enabled)
    #[cfg(feature = "websocket")]
    pub events: Option<Arc<crate::websocket::EventBroadcaster>>,
}

impl<DB: Send + Sync> AppState<DB> {
    /// Create a new AppState with just a database
    pub fn new(db: Arc<DB>) -> Self {
        Self {
            db,
            #[cfg(feature = "metrics")]
            metrics: None,
            #[cfg(feature = "rate-limit")]
            rate_limiter: None,
            #[cfg(feature = "auth")]
            auth: None,
            #[cfg(feature = "websocket")]
            events: None,
        }
    }

    /// Add metrics collector to the state
    #[cfg(feature = "metrics")]
    pub fn with_metrics(mut self, metrics: Arc<crate::metrics::MetricsCollector>) -> Self {
        self.metrics = Some(metrics);
        self
    }

    /// Add rate limiter to the state
    #[cfg(feature = "rate-limit")]
    pub fn with_rate_limiter(mut self, rate_limiter: Arc<crate::rate_limit::RateLimiter>) -> Self {
        self.rate_limiter = Some(rate_limiter);
        self
    }

    /// Add authentication provider to the state
    #[cfg(feature = "auth")]
    pub fn with_auth(mut self, auth: Arc<crate::auth::AuthProvider>) -> Self {
        self.auth = Some(auth);
        self
    }

    /// Add event broadcaster to the state
    #[cfg(feature = "websocket")]
    pub fn with_events(mut self, events: Arc<crate::websocket::EventBroadcaster>) -> Self {
        self.events = Some(events);
        self
    }
}

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

    // Mock database for testing
    #[derive(Clone)]
    struct MockDb;

    #[test]
    fn test_app_state_creation() {
        let db = Arc::new(MockDb);
        let state = AppState::new(db.clone());
        assert!(Arc::ptr_eq(&state.db, &db));
    }

    #[test]
    #[cfg(feature = "metrics")]
    fn test_app_state_with_metrics() {
        use crate::metrics::MetricsCollector;

        let db = Arc::new(MockDb);
        let metrics = Arc::new(MetricsCollector::new(&[1.0, 5.0, 10.0]).unwrap());
        let state = AppState::new(db).with_metrics(metrics.clone());
        assert!(state.metrics.is_some());
        assert!(Arc::ptr_eq(state.metrics.as_ref().unwrap(), &metrics));
    }
}
