//! Compliance module tests

use std::sync::Arc;

use tempfile::TempDir;

use super::super::*;
use crate::audit::{AuditLogger, AuditLoggerConfig, FileStorage};
use crate::compliance::{ComplianceConfig, ComplianceService, IncidentStatus, RiskLevel};

async fn setup_compliance_service() -> (ComplianceService, TempDir) {
    let temp_dir = TempDir::new().unwrap();

    // Create audit logger
    let audit_storage = Arc::new(
        FileStorage::new(temp_dir.path().join("audit"), 10 * 1024 * 1024)
            .await
            .unwrap(),
    );
    let audit_logger = Arc::new(
        AuditLogger::new(AuditLoggerConfig::default(), audit_storage)
            .await
            .unwrap(),
    );

    // Create compliance config
    let mut config = ComplianceConfig::default();
    config.gdpr.data_storage_path = temp_dir.path().join("gdpr").to_string_lossy().to_string();
    config.soc2.evidence_storage_path = temp_dir.path().join("soc2").to_string_lossy().to_string();
    config.iso27001.storage_path = temp_dir
        .path()
        .join("iso27001")
        .to_string_lossy()
        .to_string();
    config.incident_response.storage_path = temp_dir
        .path()
        .join("incidents")
        .to_string_lossy()
        .to_string();

    // Create compliance service
    let service = ComplianceService::new(audit_logger, config).await.unwrap();

    (service, temp_dir)
}

#[tokio::test]
async fn test_compliance_health_check() {
    let (service, _temp) = setup_compliance_service().await;

    let health = service.health_check().await.unwrap();

    assert!(health.gdpr_operational);
    assert!(health.soc2_operational);
    assert!(health.iso27001_operational);
    assert!(health.data_protection_operational);
    assert!(health.incident_response_operational);
}

#[tokio::test]
async fn test_gdpr_export_data() {
    let (service, _temp) = setup_compliance_service().await;

    let export = service
        .gdpr
        .export_personal_data("test_user")
        .await
        .unwrap();

    assert_eq!(export.user_id, "test_user");
    assert!(!export.data_categories.is_empty());
    assert_eq!(export.format, ExportFormat::Json);
}

#[tokio::test]
async fn test_gdpr_delete_data() {
    let (service, _temp) = setup_compliance_service().await;

    let report = service
        .gdpr
        .delete_personal_data("test_user", ErasureReason::UserRequest)
        .await
        .unwrap();

    assert_eq!(report.user_id, "test_user");
    assert_eq!(report.reason, ErasureReason::UserRequest);
    assert!(!report.deleted_from.is_empty());
    assert!(!report.verification_hash.is_empty());
}

#[tokio::test]
async fn test_soc2_report_generation() {
    let (service, _temp) = setup_compliance_service().await;

    let report = service.soc2.generate_report().await.unwrap();

    assert!(!report.id.is_empty());
    assert_eq!(report.criteria.len(), 9); // CC1 through CC9
    assert!(matches!(
        report.overall_status,
        ComplianceStatus::Compliant | ComplianceStatus::PartiallyCompliant
    ));
}

#[tokio::test]
async fn test_iso27001_report_generation() {
    let (service, _temp) = setup_compliance_service().await;

    let report = service.iso27001.generate_report().await.unwrap();

    assert!(!report.id.is_empty());
    assert_eq!(report.controls.len(), 14); // A.5 through A.18
}

#[tokio::test]
async fn test_data_classification() {
    let (service, _temp) = setup_compliance_service().await;

    // Test different classification levels
    let secret_class = service.data_protection.classify_data("secret key");
    assert_eq!(secret_class, DataClassification::Restricted);

    let confidential_class = service.data_protection.classify_data("confidential report");
    assert_eq!(confidential_class, DataClassification::Confidential);

    let internal_class = service.data_protection.classify_data("internal memo");
    assert_eq!(internal_class, DataClassification::Internal);

    let public_class = service.data_protection.classify_data("public announcement");
    assert_eq!(public_class, DataClassification::Public);
}

#[tokio::test]
async fn test_access_control_permissions() {
    let (service, _temp) = setup_compliance_service().await;

    // Test admin permissions
    assert!(service
        .access_control
        .check_permission("admin", "server:create"));
    assert!(service
        .access_control
        .check_permission("admin", "taskserv:delete"));

    // Test operator permissions
    assert!(service
        .access_control
        .check_permission("operator", "server:create"));
    assert!(service
        .access_control
        .check_permission("operator", "taskserv:read"));
    assert!(!service
        .access_control
        .check_permission("operator", "taskserv:delete"));

    // Test viewer permissions
    assert!(service
        .access_control
        .check_permission("viewer", "server:read"));
    assert!(!service
        .access_control
        .check_permission("viewer", "server:create"));
}

#[tokio::test]
async fn test_incident_reporting() {
    let (service, _temp) = setup_compliance_service().await;

    use crate::compliance::incident_response::{IncidentReport, IncidentUpdate, Resolution};

    // Report incident
    let report = IncidentReport {
        severity: IncidentSeverity::High,
        incident_type: IncidentType::UnauthorizedAccess,
        description: "Unauthorized access attempt detected".to_string(),
        affected_systems: vec!["web-server-01".to_string()],
        affected_users: vec!["user123".to_string()],
        reported_by: "security-team".to_string(),
    };

    let incident_id = service
        .incident_response
        .report_incident(report)
        .await
        .unwrap();
    assert!(!incident_id.is_empty());

    // Get incident
    let incident = service
        .incident_response
        .get_incident(&incident_id)
        .await
        .unwrap();
    assert_eq!(incident.id, incident_id);
    assert_eq!(incident.severity, IncidentSeverity::High);
    assert_eq!(incident.incident_type, IncidentType::UnauthorizedAccess);
    assert_eq!(incident.status, IncidentStatus::Detected);

    // Update incident
    let update = IncidentUpdate {
        status: Some(IncidentStatus::Contained),
        root_cause: Some("Weak password".to_string()),
        lessons_learned: None,
        updated_by: "incident-manager".to_string(),
    };

    service
        .incident_response
        .update_incident(&incident_id, update)
        .await
        .unwrap();

    // Verify update
    let updated = service
        .incident_response
        .get_incident(&incident_id)
        .await
        .unwrap();
    assert_eq!(updated.status, IncidentStatus::Contained);
    assert_eq!(updated.root_cause, Some("Weak password".to_string()));

    // Close incident
    let resolution = Resolution {
        summary: "Password policy strengthened, access revoked".to_string(),
        closed_by: "security-lead".to_string(),
    };

    service
        .incident_response
        .close_incident(&incident_id, resolution)
        .await
        .unwrap();

    // Verify closure
    let closed = service
        .incident_response
        .get_incident(&incident_id)
        .await
        .unwrap();
    assert_eq!(closed.status, IncidentStatus::Closed);
}

#[tokio::test]
async fn test_incident_filtering() {
    let (service, _temp) = setup_compliance_service().await;

    use crate::compliance::incident_response::{IncidentFilter, IncidentReport};

    // Report multiple incidents with different severities
    for i in 0..3 {
        let report = IncidentReport {
            severity: if i == 0 {
                IncidentSeverity::Critical
            } else {
                IncidentSeverity::Medium
            },
            incident_type: IncidentType::PolicyViolation,
            description: format!("Test incident {}", i),
            affected_systems: vec![],
            affected_users: vec![],
            reported_by: "test".to_string(),
        };
        service
            .incident_response
            .report_incident(report)
            .await
            .unwrap();
    }

    // Filter by severity
    let filter = IncidentFilter {
        severity: Some(IncidentSeverity::Critical),
        status: None,
        incident_type: None,
    };

    let filtered = service
        .incident_response
        .list_incidents(Some(filter))
        .await
        .unwrap();
    assert_eq!(filtered.len(), 1);
    assert_eq!(filtered[0].severity, IncidentSeverity::Critical);
}

#[tokio::test]
async fn test_data_protection_verification() {
    let (service, _temp) = setup_compliance_service().await;

    let report = service.data_protection.verify_protection().await.unwrap();

    assert!(report.encryption.at_rest_enabled);
    assert_eq!(report.encryption.algorithm, "AES-256-GCM");
    assert!(report.encryption.key_rotation_enabled);

    assert!(report.access_control.rbac_enabled);
    assert!(report.access_control.mfa_enforced);
    assert_eq!(report.access_control.session_timeout, 3600);

    assert_eq!(report.network_security.tls_version, "TLS 1.3");
    assert!(report.network_security.certificate_valid);
    assert!(report.network_security.firewall_enabled);
}
