//! Enhanced authentication middleware with JWT validation and token revocation
//!
//! This middleware:
//! 1. Extracts Authorization header
//! 2. Parses Bearer token
//! 3. Validates JWT signature, expiry, issuer, audience
//! 4. Checks token revocation status
//! 5. Builds security context and injects into request extensions

use std::sync::Arc;

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

use crate::middleware::security_context::SecurityContext;
use crate::security::{TokenValidationError, TokenValidator};

/// Authentication middleware state
#[derive(Clone)]
pub struct AuthMiddleware {
    /// Token validator
    validator: Arc<TokenValidator>,

    /// Enable authentication (can be disabled for development)
    enabled: bool,
}

impl AuthMiddleware {
    /// Create new authentication middleware
    pub fn new(validator: Arc<TokenValidator>) -> Self {
        Self {
            validator,
            enabled: true,
        }
    }

    /// Create authentication middleware with custom enabled flag
    pub fn with_enabled(validator: Arc<TokenValidator>, enabled: bool) -> Self {
        Self { validator, enabled }
    }

    /// Create disabled authentication middleware (development only)
    pub fn disabled() -> Self {
        // Create minimal validator (won't be used since enabled=false)
        // Use a valid test RSA public key from token tests
        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-----";
        let validator = TokenValidator::new(test_key, "dummy", "dummy")
            .unwrap_or_else(|_| panic!("Failed to create dummy validator"));

        Self {
            validator: Arc::new(validator),
            enabled: false,
        }
    }

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

/// Authentication middleware handler
pub async fn auth_middleware(
    State(auth): State<Arc<AuthMiddleware>>,
    mut request: Request,
    next: Next,
) -> Result<Response, AuthError> {
    // Skip authentication if disabled
    if !auth.is_enabled() {
        debug!("Authentication disabled, skipping validation");
        return Ok(next.run(request).await);
    }

    // Extract Authorization header
    let auth_header = request
        .headers()
        .get(header::AUTHORIZATION)
        .and_then(|h| h.to_str().ok())
        .ok_or(AuthError::MissingToken)?;

    // Parse Bearer token
    let token = parse_bearer_token(auth_header)?;

    // Validate JWT
    let validated = auth
        .validator
        .validate(&token)
        .await
        .map_err(AuthError::InvalidToken)?;

    debug!(
        user_id = %validated.claims.sub,
        workspace = %validated.claims.workspace,
        remaining_validity = %validated.remaining_validity,
        "Token validated successfully"
    );

    // Build security context
    let security_context = SecurityContext::from_token_and_request(validated.clone(), &request);

    // Store both ValidatedToken and SecurityContext in request extensions
    request.extensions_mut().insert(validated);
    request.extensions_mut().insert(security_context);

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

/// Parse Bearer token from Authorization header
fn parse_bearer_token(auth_header: &str) -> Result<String, AuthError> {
    auth_header
        .strip_prefix("Bearer ")
        .map(|s| s.to_string())
        .ok_or(AuthError::InvalidAuthorizationHeader)
}

/// Authentication error responses
#[derive(Debug)]
pub enum AuthError {
    MissingToken,
    InvalidAuthorizationHeader,
    InvalidToken(TokenValidationError),
}

impl IntoResponse for AuthError {
    fn into_response(self) -> Response {
        let (status, message) = match self {
            AuthError::MissingToken => (
                StatusCode::UNAUTHORIZED,
                "Missing Authorization header".to_string(),
            ),
            AuthError::InvalidAuthorizationHeader => (
                StatusCode::UNAUTHORIZED,
                "Invalid Authorization header format. Expected: Bearer <token>".to_string(),
            ),
            AuthError::InvalidToken(e) => {
                let status = match e {
                    TokenValidationError::Expired => {
                        warn!("Token validation failed: expired");
                        StatusCode::UNAUTHORIZED
                    }
                    TokenValidationError::Revoked => {
                        warn!("Token validation failed: revoked");
                        StatusCode::UNAUTHORIZED
                    }
                    TokenValidationError::InsufficientPermissions(_) => {
                        warn!("Token validation failed: insufficient permissions");
                        StatusCode::FORBIDDEN
                    }
                    _ => {
                        warn!("Token validation failed: {}", e);
                        StatusCode::UNAUTHORIZED
                    }
                };
                (status, format!("Token validation failed: {}", e))
            }
        };

        (status, message).into_response()
    }
}

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

    #[test]
    fn test_parse_bearer_token() {
        let header = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...";
        let result = parse_bearer_token(header);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...");
    }

    #[test]
    fn test_parse_bearer_token_missing_prefix() {
        let header = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...";
        let result = parse_bearer_token(header);
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_bearer_token_wrong_scheme() {
        let header = "Basic dXNlcjpwYXNz";
        let result = parse_bearer_token(header);
        assert!(result.is_err());
    }

    #[test]
    fn test_auth_middleware_creation() {
        // Use a pre-generated test RSA public key to avoid rand_core version conflicts
        let public_key_pem = b"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNEM/5k/
wq0FSLaKr7yl9VLqF85A7eW5XYBMjkjk9eePvmXVwz8tGVL7bVN6vhA5Wr2H8YyP
xPgm8YXFL1K0cEr9w3h+f6ydxN8VxGX3DHfGGV8sVMhYBG0WNVRqy7ByNKgGJBn8
YG3LbL7x4g9GQW4+N6RKPcxNXfLvFy4PpJqYwK0Y4+s+8YLZr9DsqFm1VDYC5y+I
xhL8sXr5iV0oMqKzDZY7UyLM4VlqvFqN4gNlM5EKrDGKzJL8vVyJ1Yk5zJX2WFDQ
UbXnFr2K8F5Y0RpjyJ3Z0C/T9K9VCjUkF7kZcJVqLUa3Q3q+cZyRkk1zFVhgV7mE
nQIDAQAB
-----END PUBLIC KEY-----";

        let validator =
            TokenValidator::new(public_key_pem, "control-center", "orchestrator").unwrap();

        let middleware = AuthMiddleware::new(Arc::new(validator));
        assert!(middleware.is_enabled());
    }

    #[test]
    fn test_auth_middleware_disabled() {
        // Create minimal valid RSA public key for testing
        let public_key_pem = b"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyVR5wJn5OBz0Yp6K5Ykn
d3z2C3Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1
q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1
q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1q7Z1
q7Z1qwIDAQAB
-----END PUBLIC KEY-----";

        // Don't use dummy validator, just verify the disabled() function works
        let middleware = AuthMiddleware::disabled();
        assert!(!middleware.is_enabled());
    }
}
