//! Configuration types for the bridge

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Bridge configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BridgeConfig {
    /// Enable/disable the bridge
    pub enabled: bool,

    /// Mode of operation
    pub mode: OperationMode,

    /// Which integrations to load
    pub integrations: Vec<IntegrationConfig>,

    /// Event bus configuration
    pub event_bus: EventBusConfig,

    /// Logging configuration
    pub logging: LoggingConfig,
}

/// Operation mode
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum OperationMode {
    /// Standalone operation (no external provisioning system)
    Standalone,

    /// Integrated with provctl
    Provctl,

    /// Integrated with provisioning system
    Provisioning,
}

impl OperationMode {
    pub fn as_str(&self) -> &str {
        match self {
            Self::Standalone => "standalone",
            Self::Provctl => "provctl",
            Self::Provisioning => "provisioning",
        }
    }
}

/// Configuration for a single integration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrationConfig {
    /// Integration name (e.g., "gitops", "valida", "audit")
    pub name: String,

    /// Enable/disable this integration
    #[serde(default = "default_true")]
    pub enabled: bool,

    /// Integration-specific configuration
    pub config: HashMap<String, serde_json::Value>,
}

fn default_true() -> bool {
    true
}

impl IntegrationConfig {
    pub fn new(name: String) -> Self {
        Self {
            name,
            enabled: true,
            config: HashMap::new(),
        }
    }

    pub fn with_config(mut self, key: String, value: serde_json::Value) -> Self {
        self.config.insert(key, value);
        self
    }
}

/// Event bus configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventBusConfig {
    /// Channel capacity
    #[serde(default = "default_capacity")]
    pub capacity: usize,

    /// Enable event persistence
    #[serde(default)]
    pub persist_events: bool,

    /// Event retention time in seconds
    pub retention_secs: Option<u64>,
}

fn default_capacity() -> usize {
    100
}

/// Logging configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
    /// Log level filter
    #[serde(default = "default_log_level")]
    pub level: String,

    /// Enable JSON logging
    #[serde(default)]
    pub json: bool,

    /// Log file path (if any)
    pub file: Option<String>,
}

fn default_log_level() -> String {
    "info".to_string()
}

impl Default for BridgeConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            mode: OperationMode::Standalone,
            integrations: vec![],
            event_bus: EventBusConfig {
                capacity: 100,
                persist_events: false,
                retention_secs: None,
            },
            logging: LoggingConfig {
                level: "info".to_string(),
                json: false,
                file: None,
            },
        }
    }
}

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

    #[test]
    fn test_operation_mode_display() {
        assert_eq!(OperationMode::Standalone.as_str(), "standalone");
        assert_eq!(OperationMode::Provctl.as_str(), "provctl");
        assert_eq!(OperationMode::Provisioning.as_str(), "provisioning");
    }

    #[test]
    fn test_integration_config_builder() {
        let config = IntegrationConfig::new("gitops".to_string()).with_config(
            "endpoint".to_string(),
            serde_json::json!("http://localhost:3000"),
        );

        assert_eq!(config.name, "gitops");
        assert!(config.enabled);
        assert!(config.config.contains_key("endpoint"));
    }

    #[test]
    fn test_bridge_config_default() {
        let config = BridgeConfig::default();
        assert!(config.enabled);
        assert_eq!(config.mode, OperationMode::Standalone);
        assert_eq!(config.event_bus.capacity, 100);
    }

    #[test]
    fn test_bridge_config_serialization() {
        let config = BridgeConfig::default();
        let json = serde_json::to_string(&config).unwrap();
        let deserialized: BridgeConfig = serde_json::from_str(&json).unwrap();
        assert_eq!(config.mode, deserialized.mode);
    }
}
