//! Configuration types for the ACP Server
//!
//! This module defines configuration types for the ACP Server, including
//! server settings, connection limits, and CORS configuration.

use serde::{Deserialize, Serialize};

/// Default port for the ACP Server
pub const DEFAULT_PORT: u16 = 3001;

/// Default maximum number of concurrent connections
pub const DEFAULT_MAX_CONNECTIONS: usize = 100;

/// Configuration for the ACP Server
///
/// This struct contains all configurable options for the ACP Server,
/// including network settings, security options, and resource limits.
///
/// **Note**: This config is used when starting an actual TCP server
/// (separate port mode only). For integrated mode (mounting at /acp),
/// the port field is still required but represents which port was chosen
/// for the separate server path. Higher-level configs (dirigent_core, api)
/// use `Option<u16>` to represent the integrated vs separate distinction.
///
/// TODO: Consider moving the AcpPortConfig enum from web package to core
/// and using it here to make the integrated/separate distinction explicit.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AcpServerConfig {
    /// Whether the ACP Server is enabled
    ///
    /// When disabled, the server will not accept incoming connections.
    /// Default: false
    #[serde(default)]
    pub enabled: bool,

    /// The port to listen on for incoming connections
    ///
    /// This is always a concrete port number because this config is used
    /// to start an actual TCP server. Use Option<u16> in higher-level configs
    /// to represent integrated mode (None) vs separate mode (Some(port)).
    ///
    /// Default: 3001
    #[serde(default = "default_port")]
    pub port: u16,

    /// List of allowed origins for CORS
    ///
    /// When Some, only requests from these origins are allowed.
    /// When None, all origins are allowed (use with caution).
    ///
    /// Example: ["http://localhost:3000", "https://app.example.com"]
    #[serde(default)]
    pub allowed_origins: Option<Vec<String>>,

    /// Maximum number of concurrent client connections
    ///
    /// New connections will be rejected when this limit is reached.
    /// Default: 100
    #[serde(default = "default_max_connections")]
    pub max_connections: usize,
}

/// Returns the default port value
fn default_port() -> u16 {
    DEFAULT_PORT
}

/// Returns the default max connections value
fn default_max_connections() -> usize {
    DEFAULT_MAX_CONNECTIONS
}

impl Default for AcpServerConfig {
    fn default() -> Self {
        Self {
            enabled: false,
            port: DEFAULT_PORT,
            allowed_origins: None,
            max_connections: DEFAULT_MAX_CONNECTIONS,
        }
    }
}

impl AcpServerConfig {
    /// Create a new configuration with default values
    pub fn new() -> Self {
        Self::default()
    }

    /// Create a configuration with the server enabled
    pub fn enabled() -> Self {
        Self {
            enabled: true,
            ..Default::default()
        }
    }

    /// Create a configuration with a specific port
    pub fn with_port(port: u16) -> Self {
        Self {
            port,
            ..Default::default()
        }
    }

    /// Set whether the server is enabled
    pub fn set_enabled(mut self, enabled: bool) -> Self {
        self.enabled = enabled;
        self
    }

    /// Set the port
    pub fn set_port(mut self, port: u16) -> Self {
        self.port = port;
        self
    }

    /// Set the allowed origins
    pub fn set_allowed_origins(mut self, origins: Option<Vec<String>>) -> Self {
        self.allowed_origins = origins;
        self
    }

    /// Set the maximum number of connections
    pub fn set_max_connections(mut self, max: usize) -> Self {
        self.max_connections = max;
        self
    }

    /// Check if the configuration is valid
    pub fn validate(&self) -> Result<(), String> {
        if self.port == 0 {
            return Err("Port cannot be 0".to_string());
        }

        if self.max_connections == 0 {
            return Err("max_connections must be at least 1".to_string());
        }

        Ok(())
    }
}

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

    #[test]
    fn test_default_config() {
        let config = AcpServerConfig::default();
        assert!(!config.enabled);
        assert_eq!(config.port, DEFAULT_PORT);
        assert!(config.allowed_origins.is_none());
        assert_eq!(config.max_connections, DEFAULT_MAX_CONNECTIONS);
    }

    #[test]
    fn test_enabled_config() {
        let config = AcpServerConfig::enabled();
        assert!(config.enabled);
        assert_eq!(config.port, DEFAULT_PORT);
    }

    #[test]
    fn test_with_port() {
        let config = AcpServerConfig::with_port(8080);
        assert!(!config.enabled);
        assert_eq!(config.port, 8080);
    }

    #[test]
    fn test_builder_pattern() {
        let config = AcpServerConfig::new()
            .set_enabled(true)
            .set_port(4000)
            .set_allowed_origins(Some(vec!["http://localhost:3000".to_string()]))
            .set_max_connections(50);

        assert!(config.enabled);
        assert_eq!(config.port, 4000);
        assert_eq!(
            config.allowed_origins,
            Some(vec!["http://localhost:3000".to_string()])
        );
        assert_eq!(config.max_connections, 50);
    }

    #[test]
    fn test_validation_valid() {
        let config = AcpServerConfig::default();
        assert!(config.validate().is_ok());
    }

    #[test]
    fn test_validation_invalid_port() {
        let config = AcpServerConfig {
            port: 0,
            ..Default::default()
        };
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_validation_invalid_max_connections() {
        let config = AcpServerConfig {
            max_connections: 0,
            ..Default::default()
        };
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_serialization() {
        let config = AcpServerConfig {
            enabled: true,
            port: 3001,
            allowed_origins: Some(vec!["http://localhost:3000".to_string()]),
            max_connections: 100,
        };

        let json = serde_json::to_string(&config).unwrap();
        assert!(json.contains("\"enabled\":true"));
        assert!(json.contains("\"port\":3001"));
        assert!(json.contains("\"allowed_origins\""));
        assert!(json.contains("\"max_connections\":100"));

        // Deserialize back
        let parsed: AcpServerConfig = serde_json::from_str(&json).unwrap();
        assert_eq!(parsed, config);
    }

    #[test]
    fn test_deserialization_with_defaults() {
        // Minimal JSON with defaults
        let json = r#"{"enabled":true}"#;
        let config: AcpServerConfig = serde_json::from_str(json).unwrap();

        assert!(config.enabled);
        assert_eq!(config.port, DEFAULT_PORT);
        assert!(config.allowed_origins.is_none());
        assert_eq!(config.max_connections, DEFAULT_MAX_CONNECTIONS);
    }

    #[test]
    fn test_deserialization_empty() {
        // Empty JSON should use all defaults
        let json = "{}";
        let config: AcpServerConfig = serde_json::from_str(json).unwrap();

        assert!(!config.enabled);
        assert_eq!(config.port, DEFAULT_PORT);
        assert!(config.allowed_origins.is_none());
        assert_eq!(config.max_connections, DEFAULT_MAX_CONNECTIONS);
    }

    #[test]
    fn test_equality() {
        let config1 = AcpServerConfig::default();
        let config2 = AcpServerConfig::default();
        assert_eq!(config1, config2);

        let config3 = AcpServerConfig::enabled();
        assert_ne!(config1, config3);
    }

    #[test]
    fn test_clone() {
        let config = AcpServerConfig::enabled()
            .set_port(8080)
            .set_allowed_origins(Some(vec!["origin".to_string()]));

        let cloned = config.clone();
        assert_eq!(config, cloned);
    }
}
