//! TLS configuration for ML Training Service with mutual TLS
//!
//! This module provides enterprise-grade TLS configuration for the ML training service:
//! - Mutual TLS (mTLS) for all gRPC connections
//! - Static certificate management via config crate
//! - Client certificate validation and authentication
//! - Performance optimized for HFT requirements

use anyhow::{Context, Result};

// Re-export shared TLS types from common for backward compatibility
#[allow(unused_imports)]
pub use common::tls::{ClientIdentity, TlsProtocolVersion, UserRole};
// TLS imports - TLS feature should be enabled in Cargo.toml
use tonic::transport::{Certificate, Identity, ServerTlsConfig};
use tracing::info;


/// TLS configuration for the trading service
#[derive(Debug, Clone)]
pub struct MLTrainingServiceTlsConfig {
    /// Server certificate and private key
    pub server_identity: Identity,
    /// CA certificate for client verification
    pub ca_certificate: Certificate,
    /// Require client certificates
    pub require_client_cert: bool,
}

impl MLTrainingServiceTlsConfig {
    /// Create TLS configuration from certificate files
    pub async fn from_files(
        cert_path: &str,
        key_path: &str,
        ca_cert_path: &str,
        require_client_cert: bool,
    ) -> Result<Self> {
        info!("Loading TLS certificates from filesystem");

        // Read server certificate and key
        let cert_pem = tokio::fs::read_to_string(cert_path)
            .await
            .with_context(|| format!("Failed to read certificate file: {}", cert_path))?;

        let key_pem = tokio::fs::read_to_string(key_path)
            .await
            .with_context(|| format!("Failed to read private key file: {}", key_path))?;

        // Combine certificate and key for server identity
        let server_identity = Identity::from_pem(cert_pem, key_pem);

        // Read CA certificate for client verification
        let ca_pem = tokio::fs::read_to_string(ca_cert_path)
            .await
            .with_context(|| format!("Failed to read CA certificate file: {}", ca_cert_path))?;

        let ca_certificate = Certificate::from_pem(ca_pem);

        info!(
            "TLS certificates loaded successfully - mTLS: {}",
            require_client_cert
        );

        Ok(Self {
            server_identity,
            ca_certificate,
            require_client_cert,
        })
    }

    /// Convert to tonic ServerTlsConfig
    pub fn to_server_tls_config(&self) -> ServerTlsConfig {
        let mut tls_config = ServerTlsConfig::new().identity(self.server_identity.clone());

        if self.require_client_cert {
            tls_config = tls_config.client_ca_root(self.ca_certificate.clone());
        }

        tls_config
    }

}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;

    #[test]
    fn test_client_identity_authorization() {
        let trading_identity = ClientIdentity {
            common_name: "trader1.trading.foxhunt.internal".to_string(),
            organizational_unit: "trading".to_string(),
            serial_number: "12345".to_string(),
            issuer: "Foxhunt Trading CA".to_string(),
        };

        assert!(trading_identity.is_authorized_for_trading());
        assert!(trading_identity.is_authorized_for_readonly());
        assert_eq!(trading_identity.get_role(), UserRole::Trader);

        let readonly_identity = ClientIdentity {
            common_name: "analyst1.analytics.foxhunt.internal".to_string(),
            organizational_unit: "analytics".to_string(),
            serial_number: "12346".to_string(),
            issuer: "Foxhunt Trading CA".to_string(),
        };

        assert!(!readonly_identity.is_authorized_for_trading());
        assert!(readonly_identity.is_authorized_for_readonly());
        assert_eq!(readonly_identity.get_role(), UserRole::Analyst);
    }

    #[test]
    fn test_user_role_permissions() {
        let trader = UserRole::Trader;
        let permissions = trader.get_permissions();

        assert!(permissions.contains(&"trading.submit_order"));
        assert!(permissions.contains(&"trading.cancel_order"));
        assert!(!permissions.contains(&"system.configure"));

        let readonly = UserRole::ReadOnly;
        let readonly_permissions = readonly.get_permissions();

        assert!(!readonly_permissions.contains(&"trading.submit_order"));
        assert!(readonly_permissions.contains(&"analytics.view_data"));
    }
}
