//! MFA (Multi-Factor Authentication) verification middleware
//!
//! This middleware enforces MFA requirements for sensitive operations:
//! - Production deployments
//! - Resource deletions
//! - Configuration changes
//! - Cluster operations
//!
//! The middleware checks if the user's token includes MFA verification
//! and blocks requests to protected endpoints if MFA is not verified.

use axum::{
    extract::Request,
    http::StatusCode,
    middleware::Next,
    response::{IntoResponse, Response},
};
use tracing::{debug, warn};

use crate::middleware::security_context::SecurityContext;

/// MFA verification middleware configuration
#[derive(Clone)]
pub struct MfaMiddleware {
    /// Enable MFA enforcement (can be disabled for development)
    enabled: bool,
}

impl MfaMiddleware {
    /// Create new MFA middleware with enforcement enabled
    pub fn new() -> Self {
        Self { enabled: true }
    }

    /// Create MFA middleware with custom enabled flag
    pub fn with_enabled(enabled: bool) -> Self {
        Self { enabled }
    }

    /// Create disabled MFA middleware (development only)
    pub fn disabled() -> Self {
        Self { enabled: false }
    }

    /// Check if MFA enforcement is enabled
    pub fn is_enabled(&self) -> bool {
        self.enabled
    }
}

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

/// MFA verification middleware handler
pub async fn mfa_middleware(request: Request, next: Next) -> Result<Response, MfaError> {
    // Get security context from extensions (injected by auth middleware)
    let security_context = request
        .extensions()
        .get::<SecurityContext>()
        .ok_or(MfaError::MissingSecurityContext)?;

    // Check if endpoint requires MFA
    let path = request.uri().path();
    let method = request.method().as_str();

    if requires_mfa(method, path) {
        debug!(
            path = %path,
            method = %method,
            user = %security_context.user_id,
            "Checking MFA requirement for sensitive endpoint"
        );

        // Verify MFA status
        if !security_context.is_mfa_verified() {
            warn!(
                path = %path,
                method = %method,
                user = %security_context.user_id,
                "MFA required but not verified"
            );
            return Err(MfaError::MfaRequired);
        }

        debug!(
            path = %path,
            method = %method,
            user = %security_context.user_id,
            "MFA verified, allowing request"
        );
    }

    // Continue to next middleware/handler
    Ok(next.run(request).await)
}

/// Determine if an endpoint requires MFA verification
fn requires_mfa(method: &str, path: &str) -> bool {
    // Production environment operations
    if path.contains("/production/") || path.contains("/prod/") {
        return true;
    }

    // Deployment operations
    if path.contains("/deploy") {
        return true;
    }

    // Deletion operations (DELETE method)
    if method == "DELETE" {
        // All deletion operations require MFA
        return true;
    }

    // Server operations
    if path.contains("/servers") && (method == "POST" || method == "DELETE" || method == "PUT") {
        return true;
    }

    // Cluster operations
    if path.contains("/cluster") && (method == "POST" || method == "DELETE" || method == "PUT") {
        return true;
    }

    // Batch operations - submit and execute require MFA
    if path.contains("/batch")
        && method == "POST"
        && (path.contains("/submit") || path.contains("/execute"))
    {
        return true;
    }

    // Workflow rollback operations
    if path.contains("/rollback") {
        return true;
    }

    // Configuration changes
    if path.contains("/config") && (method == "POST" || method == "PUT" || method == "DELETE") {
        return true;
    }

    // Secret management
    if path.contains("/secret") {
        return true;
    }

    // User management
    if (path.contains("/users") || path.contains("/roles") || path.contains("/permissions"))
        && (method == "POST" || method == "PUT" || method == "DELETE")
    {
        return true;
    }

    false
}

/// MFA error responses
#[derive(Debug)]
pub enum MfaError {
    MissingSecurityContext,
    MfaRequired,
}

impl IntoResponse for MfaError {
    fn into_response(self) -> Response {
        let (status, message) = match self {
            MfaError::MissingSecurityContext => (
                StatusCode::INTERNAL_SERVER_ERROR,
                "Security context not found. Ensure authentication middleware runs first."
                    .to_string(),
            ),
            MfaError::MfaRequired => (
                StatusCode::FORBIDDEN,
                "Multi-factor authentication required for this operation. Please verify MFA and \
                 try again."
                    .to_string(),
            ),
        };

        (status, message).into_response()
    }
}

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

    #[test]
    fn test_requires_mfa_production() {
        assert!(requires_mfa("POST", "/api/v1/production/deploy"));
        assert!(requires_mfa("DELETE", "/api/v1/prod/servers/123"));
        assert!(requires_mfa("PUT", "/api/v1/production/config"));
    }

    #[test]
    fn test_requires_mfa_deletion() {
        assert!(requires_mfa("DELETE", "/api/v1/servers/123"));
        assert!(requires_mfa("DELETE", "/api/v1/taskserv/kubernetes"));
        assert!(requires_mfa("DELETE", "/api/v1/cluster/prod-cluster"));
        assert!(requires_mfa("DELETE", "/api/v1/config/settings"));
    }

    #[test]
    fn test_requires_mfa_deployments() {
        assert!(requires_mfa("POST", "/api/v1/deploy/kubernetes"));
        assert!(requires_mfa("POST", "/api/v1/workflows/deploy"));
    }

    #[test]
    fn test_requires_mfa_server_operations() {
        assert!(requires_mfa("POST", "/api/v1/servers"));
        assert!(requires_mfa("PUT", "/api/v1/servers/123"));
        assert!(requires_mfa("DELETE", "/api/v1/servers/123"));
        assert!(!requires_mfa("GET", "/api/v1/servers"));
    }

    #[test]
    fn test_requires_mfa_cluster_operations() {
        assert!(requires_mfa("POST", "/api/v1/cluster"));
        assert!(requires_mfa("PUT", "/api/v1/cluster/prod"));
        assert!(requires_mfa("DELETE", "/api/v1/cluster/prod"));
        assert!(!requires_mfa("GET", "/api/v1/cluster"));
    }

    #[test]
    fn test_requires_mfa_batch_operations() {
        assert!(requires_mfa("POST", "/api/v1/batch/submit"));
        assert!(requires_mfa("POST", "/api/v1/batch/execute"));
        assert!(!requires_mfa("GET", "/api/v1/batch/status/123"));
    }

    #[test]
    fn test_requires_mfa_rollback() {
        assert!(requires_mfa("POST", "/api/v1/workflows/123/rollback"));
        assert!(requires_mfa("POST", "/api/v1/batch/456/rollback"));
    }

    #[test]
    fn test_requires_mfa_config_changes() {
        assert!(requires_mfa("POST", "/api/v1/config"));
        assert!(requires_mfa("PUT", "/api/v1/config/settings"));
        assert!(requires_mfa("DELETE", "/api/v1/config/cache"));
        assert!(!requires_mfa("GET", "/api/v1/config"));
    }

    #[test]
    fn test_requires_mfa_secrets() {
        assert!(requires_mfa("GET", "/api/v1/secret/database"));
        assert!(requires_mfa("POST", "/api/v1/secret"));
        assert!(requires_mfa("DELETE", "/api/v1/secret/123"));
    }

    #[test]
    fn test_requires_mfa_user_management() {
        assert!(requires_mfa("POST", "/api/v1/users"));
        assert!(requires_mfa("PUT", "/api/v1/users/123"));
        assert!(requires_mfa("DELETE", "/api/v1/users/123"));
        assert!(requires_mfa("POST", "/api/v1/roles"));
        assert!(requires_mfa("PUT", "/api/v1/permissions"));
        assert!(!requires_mfa("GET", "/api/v1/users"));
    }

    #[test]
    fn test_does_not_require_mfa() {
        assert!(!requires_mfa("GET", "/api/v1/health"));
        assert!(!requires_mfa("GET", "/api/v1/servers"));
        assert!(!requires_mfa("GET", "/api/v1/workflows"));
        assert!(!requires_mfa("GET", "/api/v1/dev/servers"));
    }

    #[test]
    fn test_mfa_middleware_creation() {
        let middleware = MfaMiddleware::new();
        assert!(middleware.is_enabled());

        let disabled = MfaMiddleware::disabled();
        assert!(!disabled.is_enabled());

        let custom = MfaMiddleware::with_enabled(false);
        assert!(!custom.is_enabled());
    }
}
