use crate::event::config::NotifierConfig;
use crate::ObservabilityConfig;

/// RustFs configuration
pub struct RustFsConfig {
    pub observability: ObservabilityConfig,
    pub event: NotifierConfig,
}

impl RustFsConfig {
    pub fn new() -> Self {
        Self {
            observability: ObservabilityConfig::new(),
            event: NotifierConfig::new(),
        }
    }
}

impl Default for RustFsConfig {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn test_rustfs_config_new() {
        let config = RustFsConfig::new();

        // Verify that observability config is properly initialized
        assert!(!config.observability.sinks.is_empty(), "Observability sinks should not be empty");
        assert!(config.observability.logger.is_some(), "Logger config should be present");

        // Verify that event config is properly initialized
        assert!(!config.event.store_path.is_empty(), "Event store path should not be empty");
        assert!(config.event.channel_capacity > 0, "Channel capacity should be positive");
        assert!(!config.event.adapters.is_empty(), "Event adapters should not be empty");
    }

    #[test]
    fn test_rustfs_config_default() {
        let config = RustFsConfig::default();

        // Default should be equivalent to new()
        let new_config = RustFsConfig::new();

        // Compare observability config
        assert_eq!(config.observability.sinks.len(), new_config.observability.sinks.len());
        assert_eq!(config.observability.logger.is_some(), new_config.observability.logger.is_some());

        // Compare event config
        assert_eq!(config.event.store_path, new_config.event.store_path);
        assert_eq!(config.event.channel_capacity, new_config.event.channel_capacity);
        assert_eq!(config.event.adapters.len(), new_config.event.adapters.len());
    }

    #[test]
    fn test_rustfs_config_components_independence() {
        let mut config = RustFsConfig::new();

        // Modify observability config
        config.observability.sinks.clear();

        // Event config should remain unchanged
        assert!(!config.event.adapters.is_empty(), "Event adapters should remain unchanged");
        assert!(config.event.channel_capacity > 0, "Channel capacity should remain unchanged");

        // Create new config to verify independence
        let new_config = RustFsConfig::new();
        assert!(!new_config.observability.sinks.is_empty(), "New config should have default sinks");
    }

    #[test]
    fn test_rustfs_config_observability_integration() {
        let config = RustFsConfig::new();

        // Test observability config properties
        assert!(config.observability.otel.endpoint.is_empty() || !config.observability.otel.endpoint.is_empty());
        assert!(config.observability.otel.use_stdout.is_some());
        assert!(config.observability.otel.sample_ratio.is_some());
        assert!(config.observability.otel.meter_interval.is_some());
        assert!(config.observability.otel.service_name.is_some());
        assert!(config.observability.otel.service_version.is_some());
        assert!(config.observability.otel.environment.is_some());
        assert!(config.observability.otel.logger_level.is_some());
    }

    #[test]
    fn test_rustfs_config_event_integration() {
        let config = RustFsConfig::new();

        // Test event config properties
        assert!(!config.event.store_path.is_empty(), "Store path should not be empty");
        assert!(
            config.event.channel_capacity >= 1000,
            "Channel capacity should be reasonable for production"
        );

        // Test that store path is a valid path format
        let store_path = &config.event.store_path;
        assert!(!store_path.contains('\0'), "Store path should not contain null characters");

        // Test adapters configuration
        for adapter in &config.event.adapters {
            // Each adapter should have a valid configuration
            match adapter {
                crate::event::adapters::AdapterConfig::Webhook(_) => {
                    // Webhook adapter should be properly configured
                }
                crate::event::adapters::AdapterConfig::Kafka(_) => {
                    // Kafka adapter should be properly configured
                }
                crate::event::adapters::AdapterConfig::Mqtt(_) => {
                    // MQTT adapter should be properly configured
                }
            }
        }
    }

    #[test]
    fn test_rustfs_config_memory_usage() {
        // Test that config doesn't use excessive memory
        let config = RustFsConfig::new();

        // Basic memory usage checks
        assert!(std::mem::size_of_val(&config) < 10000, "Config should not use excessive memory");

        // Test that strings are not excessively long
        assert!(config.event.store_path.len() < 1000, "Store path should not be excessively long");

        // Test that collections are reasonably sized
        assert!(config.observability.sinks.len() < 100, "Sinks collection should be reasonably sized");
        assert!(config.event.adapters.len() < 100, "Adapters collection should be reasonably sized");
    }

    #[test]
    fn test_rustfs_config_serialization_compatibility() {
        let config = RustFsConfig::new();

        // Test that observability config can be serialized (it has Serialize trait)
        let observability_json = serde_json::to_string(&config.observability);
        assert!(observability_json.is_ok(), "Observability config should be serializable");

        // Test that event config can be serialized (it has Serialize trait)
        let event_json = serde_json::to_string(&config.event);
        assert!(event_json.is_ok(), "Event config should be serializable");
    }

    #[test]
    fn test_rustfs_config_debug_format() {
        let config = RustFsConfig::new();

        // Test that observability config has Debug trait
        let observability_debug = format!("{:?}", config.observability);
        assert!(!observability_debug.is_empty(), "Observability config should have debug output");
        assert!(
            observability_debug.contains("ObservabilityConfig"),
            "Debug output should contain type name"
        );

        // Test that event config has Debug trait
        let event_debug = format!("{:?}", config.event);
        assert!(!event_debug.is_empty(), "Event config should have debug output");
        assert!(event_debug.contains("NotifierConfig"), "Debug output should contain type name");
    }

    #[test]
    fn test_rustfs_config_clone_behavior() {
        let config = RustFsConfig::new();

        // Test that observability config can be cloned
        let observability_clone = config.observability.clone();
        assert_eq!(observability_clone.sinks.len(), config.observability.sinks.len());

        // Test that event config can be cloned
        let event_clone = config.event.clone();
        assert_eq!(event_clone.store_path, config.event.store_path);
        assert_eq!(event_clone.channel_capacity, config.event.channel_capacity);
    }

    #[test]
    fn test_rustfs_config_environment_independence() {
        // Test that config creation doesn't depend on specific environment variables
        // This test ensures the config can be created in any environment

        let config1 = RustFsConfig::new();
        let config2 = RustFsConfig::new();

        // Both configs should have the same structure
        assert_eq!(config1.observability.sinks.len(), config2.observability.sinks.len());
        assert_eq!(config1.event.adapters.len(), config2.event.adapters.len());

        // Store paths should be consistent
        assert_eq!(config1.event.store_path, config2.event.store_path);
        assert_eq!(config1.event.channel_capacity, config2.event.channel_capacity);
    }
}
