// Audit logging tests for secret access tracking

#[cfg(test)]
#[allow(clippy::module_inception)] // Reason: test module mirrors source module structure for clarity
mod audit_logging {
    use std::{collections::VecDeque, sync::Mutex};

    /// Audit log entry structure
    #[derive(Debug, Clone, PartialEq, Eq)]
    pub struct AuditLogEntry {
        pub event_type:    String,
        pub secret_type:   String,
        pub subject:       Option<String>,
        pub operation:     String,
        pub success:       bool,
        pub error_message: Option<String>,
        pub timestamp:     u64,
    }

    /// Mock audit logger for testing
    pub struct MockAuditLogger {
        logs: Mutex<VecDeque<AuditLogEntry>>,
    }

    impl MockAuditLogger {
        pub fn new() -> Self {
            Self {
                logs: Mutex::new(VecDeque::new()),
            }
        }

        pub fn log_entry(&self, entry: AuditLogEntry) {
            self.logs.lock().unwrap().push_back(entry);
        }

        pub fn get_logs(&self) -> Vec<AuditLogEntry> {
            self.logs.lock().unwrap().iter().cloned().collect()
        }

        pub fn clear(&self) {
            self.logs.lock().unwrap().clear();
        }
    }

    // ===== JWT VALIDATION LOGGING TESTS =====

    #[test]
    fn test_jwt_validation_success_logged() {
        let logger = MockAuditLogger::new();

        // Simulate JWT validation success
        let entry = AuditLogEntry {
            event_type:    "jwt_validation".to_string(),
            secret_type:   "jwt_token".to_string(),
            subject:       Some("user123".to_string()),
            operation:     "validate".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_890,
        };

        logger.log_entry(entry);

        // Verify log entry was recorded
        let logs = logger.get_logs();
        assert_eq!(logs.len(), 1);
        assert_eq!(logs[0].event_type, "jwt_validation");
        assert!(logs[0].success);
        assert_eq!(logs[0].subject, Some("user123".to_string()));
    }

    #[test]
    fn test_jwt_validation_failure_logged() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "jwt_validation".to_string(),
            secret_type:   "jwt_token".to_string(),
            subject:       Some("user123".to_string()),
            operation:     "validate".to_string(),
            success:       false,
            error_message: Some("Invalid signature".to_string()),
            timestamp:     1_234_567_890,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs.len(), 1);
        assert!(!(logs[0].success));
        assert!(logs[0].error_message.is_some());
    }

    #[test]
    fn test_jwt_validation_log_includes_timestamp() {
        let logger = MockAuditLogger::new();
        let timestamp = 1_234_567_890_u64;

        let entry = AuditLogEntry {
            event_type: "jwt_validation".to_string(),
            secret_type: "jwt_token".to_string(),
            subject: Some("user123".to_string()),
            operation: "validate".to_string(),
            success: true,
            error_message: None,
            timestamp,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].timestamp, timestamp);
    }

    // ===== OIDC CREDENTIAL ACCESS LOGGING TESTS =====

    #[test]
    fn test_oidc_credential_access_logged() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "oidc_credential_access".to_string(),
            secret_type:   "client_secret".to_string(),
            subject:       Some("service-account".to_string()),
            operation:     "retrieve".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_890,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs.len(), 1);
        assert_eq!(logs[0].secret_type, "client_secret");
        assert_eq!(logs[0].operation, "retrieve");
    }

    #[test]
    fn test_oidc_token_exchange_logged() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "oidc_token_exchange".to_string(),
            secret_type:   "authorization_code".to_string(),
            subject:       Some("user456".to_string()),
            operation:     "exchange".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_891,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].event_type, "oidc_token_exchange");
        assert_eq!(logs[0].operation, "exchange");
    }

    // ===== SESSION TOKEN ACCESS LOGGING TESTS =====

    #[test]
    fn test_session_token_creation_logged() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "session_token_created".to_string(),
            secret_type:   "session_token".to_string(),
            subject:       Some("user789".to_string()),
            operation:     "create".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_892,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].event_type, "session_token_created");
        assert_eq!(logs[0].subject, Some("user789".to_string()));
    }

    #[test]
    fn test_session_token_validation_logged() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "session_token_validation".to_string(),
            secret_type:   "session_token".to_string(),
            subject:       Some("user789".to_string()),
            operation:     "validate".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_893,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].event_type, "session_token_validation");
    }

    #[test]
    fn test_session_token_revocation_logged() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "session_token_revoked".to_string(),
            secret_type:   "session_token".to_string(),
            subject:       Some("user789".to_string()),
            operation:     "revoke".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_894,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].operation, "revoke");
    }

    // ===== FAILED SECRET ACCESS LOGGING TESTS =====

    #[test]
    fn test_invalid_jwt_validation_includes_error() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "jwt_validation".to_string(),
            secret_type:   "jwt_token".to_string(),
            subject:       Some("user123".to_string()),
            operation:     "validate".to_string(),
            success:       false,
            error_message: Some("Token expired".to_string()),
            timestamp:     1_234_567_895,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert!(!logs[0].success);
        assert_eq!(logs[0].error_message, Some("Token expired".to_string()));
    }

    #[test]
    fn test_denied_oidc_credential_access_logged() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "oidc_credential_access".to_string(),
            secret_type:   "client_secret".to_string(),
            subject:       Some("service-account".to_string()),
            operation:     "retrieve".to_string(),
            success:       false,
            error_message: Some("Unauthorized access".to_string()),
            timestamp:     1_234_567_896,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs.len(), 1);
        assert!(!logs[0].success);
        assert!(logs[0].error_message.is_some());
    }

    // ===== CONTEXT AND SUBJECT TRACKING TESTS =====

    #[test]
    fn test_audit_log_includes_subject_context() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "jwt_validation".to_string(),
            secret_type:   "jwt_token".to_string(),
            subject:       Some("alice@example.com".to_string()),
            operation:     "validate".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_897,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].subject, Some("alice@example.com".to_string()));
    }

    #[test]
    fn test_audit_log_subject_optional_for_anonymous() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "public_key_fetch".to_string(),
            secret_type:   "public_key".to_string(),
            subject:       None,
            operation:     "retrieve".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_898,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].subject, None);
    }

    // ===== MULTIPLE OPERATIONS SEQUENCE TESTS =====

    #[test]
    fn test_multiple_operations_logged_in_sequence() {
        let logger = MockAuditLogger::new();

        // Simulate OAuth flow: start → callback → token exchange
        let start_entry = AuditLogEntry {
            event_type:    "oauth_start".to_string(),
            secret_type:   "state_token".to_string(),
            subject:       Some("user123".to_string()),
            operation:     "create".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1000,
        };

        let callback_entry = AuditLogEntry {
            event_type:    "oauth_callback".to_string(),
            secret_type:   "authorization_code".to_string(),
            subject:       Some("user123".to_string()),
            operation:     "verify".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1001,
        };

        let exchange_entry = AuditLogEntry {
            event_type:    "token_exchange".to_string(),
            secret_type:   "access_token".to_string(),
            subject:       Some("user123".to_string()),
            operation:     "issue".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1002,
        };

        logger.log_entry(start_entry);
        logger.log_entry(callback_entry);
        logger.log_entry(exchange_entry);

        let logs = logger.get_logs();
        assert_eq!(logs.len(), 3);
        assert_eq!(logs[0].timestamp, 1000);
        assert_eq!(logs[1].timestamp, 1001);
        assert_eq!(logs[2].timestamp, 1002);
        assert_eq!(logs[0].event_type, "oauth_start");
        assert_eq!(logs[1].event_type, "oauth_callback");
        assert_eq!(logs[2].event_type, "token_exchange");
    }

    #[test]
    fn test_audit_log_clear_for_testing() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "test_event".to_string(),
            secret_type:   "test_secret".to_string(),
            subject:       Some("test_user".to_string()),
            operation:     "test".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_899,
        };

        logger.log_entry(entry);
        assert_eq!(logger.get_logs().len(), 1);

        logger.clear();
        assert_eq!(logger.get_logs().len(), 0);
    }

    // ===== EDGE CASES =====

    #[test]
    fn test_audit_log_with_very_long_error_message() {
        let logger = MockAuditLogger::new();
        let long_error = "a".repeat(1000);

        let entry = AuditLogEntry {
            event_type:    "jwt_validation".to_string(),
            secret_type:   "jwt_token".to_string(),
            subject:       Some("user123".to_string()),
            operation:     "validate".to_string(),
            success:       false,
            error_message: Some(long_error.clone()),
            timestamp:     1_234_567_900,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].error_message.as_ref().unwrap().len(), 1000);
    }

    #[test]
    fn test_audit_log_with_special_characters_in_subject() {
        let logger = MockAuditLogger::new();

        let entry = AuditLogEntry {
            event_type:    "jwt_validation".to_string(),
            secret_type:   "jwt_token".to_string(),
            subject:       Some("user+test@example.com".to_string()),
            operation:     "validate".to_string(),
            success:       true,
            error_message: None,
            timestamp:     1_234_567_901,
        };

        logger.log_entry(entry);

        let logs = logger.get_logs();
        assert_eq!(logs[0].subject, Some("user+test@example.com".to_string()));
    }

    #[test]
    fn test_high_volume_audit_logging() {
        let logger = MockAuditLogger::new();

        // Generate 1000 log entries
        for i in 0..1000 {
            let entry = AuditLogEntry {
                event_type:    "test_event".to_string(),
                secret_type:   "test_secret".to_string(),
                subject:       Some(format!("user{}", i)),
                operation:     "test".to_string(),
                success:       i % 2 == 0,
                error_message: if i % 2 == 0 {
                    None
                } else {
                    Some("Test error".to_string())
                },
                timestamp:     1000 + i as u64,
            };

            logger.log_entry(entry);
        }

        let logs = logger.get_logs();
        assert_eq!(logs.len(), 1000);

        // Verify order is preserved
        assert_eq!(logs[0].subject, Some("user0".to_string()));
        assert_eq!(logs[999].subject, Some("user999".to_string()));
    }
}
