//! Security integration helpers for main.rs
//!
//! This module provides helpers to integrate all security components
//! into the orchestrator's AppState and middleware chain.

use std::path::PathBuf;
use std::sync::Arc;

use anyhow::{Context, Result};

use crate::audit::AuditLogger;
use crate::middleware::{
    AuthMiddleware, AuthzMiddleware, MfaMiddleware, RateLimitConfig, RateLimiter,
};
use crate::security::{CedarEngine, TokenValidator};

/// Security components for orchestrator
#[derive(Clone)]
pub struct SecurityComponents {
    /// JWT token validator
    pub token_validator: Arc<TokenValidator>,

    /// Cedar authorization engine
    pub cedar_engine: Arc<CedarEngine>,

    /// Authentication middleware
    pub auth_middleware: Arc<AuthMiddleware>,

    /// MFA verification middleware
    pub mfa_middleware: Arc<MfaMiddleware>,

    /// Authorization middleware
    pub authz_middleware: Arc<AuthzMiddleware>,

    /// Rate limiter
    pub rate_limiter: Arc<RateLimiter>,
}

/// Configuration for security components
pub struct SecurityConfig {
    /// Path to RSA public key (PEM format)
    pub public_key_path: PathBuf,

    /// JWT issuer (e.g., "control-center")
    pub jwt_issuer: String,

    /// JWT audience (e.g., "orchestrator")
    pub jwt_audience: String,

    /// Path to Cedar policies directory
    pub cedar_policies_path: PathBuf,

    /// Enable authentication (can be disabled for development)
    pub auth_enabled: bool,

    /// Enable authorization (can be disabled for development)
    pub authz_enabled: bool,

    /// Enable MFA enforcement (can be disabled for development)
    pub mfa_enabled: bool,

    /// Rate limit configuration
    pub rate_limit_config: RateLimitConfig,
}

impl Default for SecurityConfig {
    fn default() -> Self {
        Self {
            public_key_path: PathBuf::from("keys/public.pem"),
            jwt_issuer: "control-center".to_string(),
            jwt_audience: "orchestrator".to_string(),
            cedar_policies_path: PathBuf::from("policies"),
            auth_enabled: true,
            authz_enabled: true,
            mfa_enabled: true,
            rate_limit_config: RateLimitConfig::default(),
        }
    }
}

impl SecurityComponents {
    /// Initialize all security components
    pub async fn initialize(
        config: SecurityConfig,
        audit_logger: Arc<AuditLogger>,
    ) -> Result<Self> {
        // Read public key for JWT validation
        let public_key = std::fs::read(&config.public_key_path).context(format!(
            "Failed to read public key from {:?}",
            config.public_key_path
        ))?;

        // Create token validator
        let token_validator = Arc::new(
            TokenValidator::new(
                &public_key,
                config.jwt_issuer.clone(),
                config.jwt_audience.clone(),
            )
            .context("Failed to create token validator")?,
        );

        // Load Cedar policies
        let cedar_engine = if config.authz_enabled {
            Arc::new(
                CedarEngine::from_directory(&config.cedar_policies_path)
                    .await
                    .context("Failed to load Cedar policies")?,
            )
        } else {
            // Create empty engine for disabled mode
            Arc::new(CedarEngine::new())
        };

        // Create middleware components
        let auth_middleware = Arc::new(AuthMiddleware::with_enabled(
            token_validator.clone(),
            config.auth_enabled,
        ));

        let mfa_middleware = Arc::new(MfaMiddleware::with_enabled(config.mfa_enabled));

        let authz_middleware = Arc::new(AuthzMiddleware::with_enabled(
            cedar_engine.clone(),
            audit_logger.clone(),
            config.authz_enabled,
        ));

        let rate_limiter = Arc::new(RateLimiter::with_config(config.rate_limit_config));

        Ok(Self {
            token_validator,
            cedar_engine,
            auth_middleware,
            mfa_middleware,
            authz_middleware,
            rate_limiter,
        })
    }

    /// Create security components with all features disabled (development mode)
    pub fn disabled(audit_logger: Arc<AuditLogger>) -> Self {
        // Use valid test RSA public key
        let test_key = b"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNEM/5k/
wq0FSLaKr7yl9VLqF85A7eW5XYBMjkjk9eePvmXVwz8tGVL7bVN6vhA5Wr2H8YyP
xPgm8YXFL1K0cEr9w3h+f6ydxN8VxGX3DHfGGV8sVMhYBG0WNVRqy7ByNKgGJBn8
YG3LbL7x4g9GQW4+N6RKPcxNXfLvFy4PpJqYwK0Y4+s+8YLZr9DsqFm1VDYC5y+I
xhL8sXr5iV0oMqKzDZY7UyLM4VlqvFqN4gNlM5EKrDGKzJL8vVyJ1Yk5zJX2WFDQ
UbXnFr2K8F5Y0RpjyJ3Z0C/T9K9VCjUkF7kZcJVqLUa3Q3q+cZyRkk1zFVhgV7mE
nQIDAQAB
-----END PUBLIC KEY-----";

        Self {
            token_validator: Arc::new(
                TokenValidator::new(test_key, "dummy", "dummy")
                    .expect("Failed to create dummy validator"),
            ),
            cedar_engine: Arc::new(CedarEngine::new()),
            auth_middleware: Arc::new(AuthMiddleware::disabled()),
            mfa_middleware: Arc::new(MfaMiddleware::disabled()),
            authz_middleware: Arc::new(AuthzMiddleware::disabled(audit_logger)),
            rate_limiter: Arc::new(RateLimiter::with_config(RateLimitConfig::disabled())),
        }
    }
}

/// Helper to build router with complete security middleware chain
///
/// The middleware chain is applied in this order:
/// 1. Rate limiting - Prevent API abuse
/// 2. Authentication - JWT token validation
/// 3. MFA verification - Check MFA for sensitive operations
/// 4. Authorization - Cedar policy evaluation
/// 5. Audit logging - Log all requests
///
/// # Example
///
/// ```no_run
/// use axum::Router;
/// use provisioning_orchestrator::security_integration::{SecurityComponents, apply_security_middleware};
///
/// # async fn example(router: Router, security: SecurityComponents) {
/// let secured_router = apply_security_middleware(router, &security);
/// # }
/// ```
pub fn apply_security_middleware<S>(
    router: axum::Router<S>,
    security: &SecurityComponents,
) -> axum::Router<S>
where
    S: Clone + Send + Sync + 'static,
{
    use axum::middleware;

    router
        // 5. Audit middleware (innermost - sees authenticated user)
        // Already applied separately in main.rs
        // 4. Authorization middleware
        .layer(middleware::from_fn_with_state(
            security.authz_middleware.clone(),
            crate::middleware::authz_middleware,
        ))
        // 3. MFA verification middleware
        .layer(middleware::from_fn(crate::middleware::mfa_middleware))
        // 2. Authentication middleware
        .layer(middleware::from_fn_with_state(
            security.auth_middleware.clone(),
            crate::middleware::auth_middleware,
        ))
        // 1. Rate limiting middleware (outermost - first to execute)
        .layer(middleware::from_fn({
            let limiter = security.rate_limiter.clone();
            move |req, next| {
                let limiter = limiter.clone();
                async move { crate::middleware::rate_limit_middleware(limiter, req, next).await }
            }
        }))
}

#[cfg(test)]
mod tests {
    use tempfile::TempDir;

    use super::*;

    #[test]
    fn test_security_config_default() {
        let config = SecurityConfig::default();
        assert!(config.auth_enabled);
        assert!(config.authz_enabled);
        assert!(config.mfa_enabled);
        assert_eq!(config.jwt_issuer, "control-center");
        assert_eq!(config.jwt_audience, "orchestrator");
    }

    #[tokio::test]
    async fn test_security_components_disabled() {
        use crate::audit::{AuditLogger, AuditLoggerConfig, FileStorage};

        let temp_dir = TempDir::new().unwrap();
        let storage = Arc::new(
            FileStorage::new(temp_dir.path().to_path_buf(), 1024 * 1024)
                .await
                .unwrap(),
        );
        let audit_logger = Arc::new(
            AuditLogger::new(AuditLoggerConfig::default(), storage)
                .await
                .unwrap(),
        );

        let security = SecurityComponents::disabled(audit_logger);

        assert!(!security.auth_middleware.is_enabled());
        assert!(!security.mfa_middleware.is_enabled());
        assert!(!security.authz_middleware.is_enabled());
    }
}
