//! Comprehensive Compliance Validation Test Suite
//!
//! This module provides extensive tests for all compliance functionality,
//! ensuring regulatory adherence for SOX, MiFID II, and other requirements.
//! Includes property-based testing and regulatory scenario validation.
#![allow(unused_crate_dependencies)]

use chrono::{Duration, Utc};
use proptest::prelude::*;
use std::collections::HashMap;

// Import common types
use common::{OrderId, OrderSide, OrderType, Price, Quantity};
use rust_decimal::Decimal;

// Import compliance modules
use trading_engine::compliance::{
    audit_trails::{
        AuditEventType, AuditTrailConfig, AuditTrailEngine, ExecutionDetails, OrderDetails,
    },
    automated_reporting::AutomatedReportingConfig,
    best_execution::BestExecutionAnalyzer,
    regulatory_api::{RegulatoryApiConfig, RegulatoryApiServer},
    sox_compliance::{EventOutcome, SOXAuditEvent, SOXComplianceManager, SOXConfig, SOXEventType},
    transaction_reporting::{OrderExecution, TransactionReporter},
    ComplianceConfig, ComplianceEngine, ComplianceStatus, OrderInfo,
};

/// Compliance test suite
#[derive(Debug)]
pub struct ComplianceTestSuite {
    compliance_engine: ComplianceEngine,
    sox_manager: SOXComplianceManager,
    transaction_reporter: TransactionReporter,
    audit_trail_engine: AuditTrailEngine,
}

impl ComplianceTestSuite {
    /// Create new test suite with default configuration
    pub fn new() -> Self {
        let compliance_config = ComplianceConfig::default();
        let sox_config = SOXConfig::default();
        let audit_config = AuditTrailConfig::default();

        Self {
            compliance_engine: ComplianceEngine::new(compliance_config.clone()),
            sox_manager: SOXComplianceManager::new(&sox_config),
            transaction_reporter: TransactionReporter::new(&compliance_config.mifid2),
            audit_trail_engine: AuditTrailEngine::new(audit_config),
        }
    }
}

/// Test basic compliance engine functionality
#[tokio::test]
async fn test_compliance_engine_basic_functionality() {
    let test_suite = ComplianceTestSuite::new();

    // Create test context
    let context = create_test_compliance_context();

    // Assess compliance
    let result = test_suite
        .compliance_engine
        .assess_compliance(&context)
        .await;
    assert!(result.is_ok(), "Compliance assessment should succeed");

    let compliance_result = result.unwrap();
    assert!(
        compliance_result.compliance_score >= 0.0 && compliance_result.compliance_score <= 100.0,
        "Compliance score should be between 0 and 100"
    );
}

/// Test SOX compliance manager
#[tokio::test]
async fn test_sox_compliance_manager() {
    let test_suite = ComplianceTestSuite::new();

    // Test SOX compliance assessment
    let assessment = test_suite.sox_manager.assess_sox_compliance().await;
    assert!(assessment.is_ok(), "SOX assessment should succeed");

    let sox_result = assessment.unwrap();
    assert!(
        sox_result.overall_score >= 0.0,
        "SOX score should be non-negative"
    );
}

/// Test SOX audit logging
#[tokio::test]
async fn test_sox_audit_logging() {
    let test_suite = ComplianceTestSuite::new();
    let sox_manager = test_suite.sox_manager;

    // Create test audit event
    let _audit_event = SOXAuditEvent {
        event_id: "TEST-001".to_string(),
        event_type: SOXEventType::ControlTesting,
        timestamp: Utc::now(),
        actor: "test_user".to_string(),
        resource: "test_control".to_string(),
        details: HashMap::new(),
        outcome: EventOutcome::Success,
        ip_address: Some("127.0.0.1".to_string()),
        session_id: Some("session_123".to_string()),
    };

    // Test audit logging (note: this would need access to the audit_logger field)
    // For now, just verify the manager exists
    assert!(format!("{:?}", sox_manager).contains("SOXComplianceManager"));
}

/// Test MiFID II transaction reporting
#[tokio::test]
async fn test_mifid2_transaction_reporting() {
    let test_suite = ComplianceTestSuite::new();

    // Create test execution
    let execution = create_test_order_execution();

    // Generate transaction report
    let report = test_suite
        .transaction_reporter
        .generate_transaction_report(&execution)
        .await;
    assert!(
        report.is_ok(),
        "Transaction report generation should succeed"
    );

    let transaction_report = report.unwrap();
    assert!(
        !transaction_report.header.report_id.is_empty(),
        "Report should have an ID"
    );
    assert_eq!(
        transaction_report.transaction.transaction_reference,
        execution.execution_id
    );
}

/// Test transaction audit trails
#[tokio::test]
async fn test_transaction_audit_trails() {
    let test_suite = ComplianceTestSuite::new();

    // Test order creation logging
    let order_details = create_test_order_details();
    let result = test_suite
        .audit_trail_engine
        .log_order_created("ORDER-123", &order_details);
    assert!(result.is_ok(), "Order creation logging should succeed");

    // Test execution logging
    let execution_details = create_test_execution_details();
    let result = test_suite
        .audit_trail_engine
        .log_order_executed(&execution_details);
    assert!(result.is_ok(), "Execution logging should succeed");
}

/// Test best execution analysis
#[tokio::test]
async fn test_best_execution_analysis() {
    let compliance_config = ComplianceConfig::default();
    let analyzer = BestExecutionAnalyzer::new(&compliance_config.mifid2);

    let order = create_test_order_info();

    // Analyze best execution
    let analysis = analyzer.analyze_best_execution(&order).await;
    assert!(analysis.is_ok(), "Best execution analysis should succeed");

    let execution_report = analysis.unwrap();
    assert!(
        execution_report.execution_quality_score >= 0.0
            && execution_report.execution_quality_score <= 100.0,
        "Execution quality score should be between 0 and 100"
    );
}

// Property-based test for compliance scores
proptest! {
    #[test]
    fn prop_test_compliance_scores(
        score in 0.0f64..=100.0f64
    ) {
        // Test that compliance scores are always in valid range
        prop_assert!(score >= 0.0 && score <= 100.0);
    }
}

// Property-based test for order quantities
proptest! {
    #[test]
    fn prop_test_order_quantities(
        quantity in 1u64..=1_000_000u64
    ) {
        let decimal_quantity = Decimal::from(quantity);

        // Test that order quantities are positive
        prop_assert!(decimal_quantity > Decimal::ZERO);

        // Test audit trail logging with various quantities
        let order_details = OrderDetails {
            transaction_id: "PROP-TEST".to_string(),
            user_id: "test_user".to_string(),
            session_id: Some("session_123".to_string()),
            client_ip: Some("127.0.0.1".to_string()),
            symbol: "AAPL".to_string(),
            quantity: decimal_quantity,
            price: Some(Decimal::from(150)),
            side: "BUY".to_string(),
            order_type: "LIMIT".to_string(),
            venue: Some("NYSE".to_string()),
            account_id: "ACC-123".to_string(),
            strategy_id: Some("STRAT-001".to_string()),
            metadata: HashMap::new(),
        };

        let audit_config = AuditTrailConfig::default();
        let audit_engine = AuditTrailEngine::new(audit_config);
        let result = audit_engine.log_order_created("PROP-ORDER", &order_details);
        prop_assert!(result.is_ok());
    }
}

/// Test regulatory API endpoints
#[tokio::test]
async fn test_regulatory_api_configuration() {
    let api_config = RegulatoryApiConfig::default();
    let compliance_config = ComplianceConfig::default();

    // Test API server creation
    let _api_server = RegulatoryApiServer::new(api_config.clone(), compliance_config);

    // Verify configuration
    assert_eq!(api_config.http_port, 8080);
    assert_eq!(api_config.grpc_port, 9090);
    assert!(
        !api_config.api_keys.is_empty(),
        "Should have default API keys"
    );
}

/// Test automated reporting system
#[tokio::test]
async fn test_automated_reporting_system() {
    let reporting_config = AutomatedReportingConfig::default();

    // Verify default schedules exist
    assert!(
        !reporting_config.schedules.is_empty(),
        "Should have default schedules"
    );

    // Verify MiFID II daily reports schedule exists
    let mifid_schedule = reporting_config
        .schedules
        .iter()
        .find(|s| s.schedule_id == "daily_mifid_reports");
    assert!(
        mifid_schedule.is_some(),
        "Should have MiFID II daily reports schedule"
    );

    // Verify SOX quarterly assessment schedule exists
    let sox_schedule = reporting_config
        .schedules
        .iter()
        .find(|s| s.schedule_id == "quarterly_sox_assessment");
    assert!(
        sox_schedule.is_some(),
        "Should have SOX quarterly assessment schedule"
    );
}

/// Test compliance configuration validation
#[test]
fn test_compliance_configuration_validation() {
    let config = ComplianceConfig::default();

    // Test MiFID II configuration
    assert!(
        config.mifid2.best_execution_enabled,
        "Best execution should be enabled by default"
    );
    assert!(
        config.mifid2.client_categorization_enabled,
        "Client categorization should be enabled"
    );

    // Test SOX configuration
    assert!(
        config.sox.management_certification_required,
        "Management certification should be required"
    );
    assert!(
        config.sox.audit_trail_required,
        "Audit trail should be required"
    );

    // Test retention period
    assert_eq!(
        config.audit_retention_days, 2555,
        "Audit retention should be 7 years"
    );
}

/// Test compliance error handling
#[tokio::test]
async fn test_compliance_error_handling() {
    let test_suite = ComplianceTestSuite::new();

    // Test with invalid context
    let invalid_context = create_invalid_compliance_context();

    // Should handle invalid context gracefully
    let result = test_suite
        .compliance_engine
        .assess_compliance(&invalid_context)
        .await;
    // Note: The actual behavior depends on implementation - could be Ok with warnings or Err
    match result {
        Ok(compliance_result) => {
            // If it succeeds, it should flag issues
            assert!(
                !compliance_result.findings.is_empty()
                    || matches!(compliance_result.status, ComplianceStatus::Warning(_))
                    || matches!(compliance_result.status, ComplianceStatus::Violation(_)),
                "Invalid context should result in findings or non-compliant status"
            );
        },
        Err(_) => {
            // Error is also acceptable for invalid context
        },
    }
}

/// Test audit trail query functionality
#[tokio::test]
async fn test_audit_trail_queries() {
    let test_suite = ComplianceTestSuite::new();

    // Create test query
    let query = trading_engine::compliance::audit_trails::AuditTrailQuery {
        start_time: Utc::now() - Duration::hours(24),
        end_time: Utc::now(),
        event_types: Some(vec![
            AuditEventType::OrderCreated,
            AuditEventType::OrderExecuted,
        ]),
        transaction_id: None,
        order_id: None,
        actor: None,
        symbol: Some("AAPL".to_string()),
        account_id: None,
        risk_level: None,
        compliance_tags: None,
        limit: Some(100),
        offset: None,
        sort_order: trading_engine::compliance::audit_trails::SortOrder::TimestampDesc,
    };

    // Execute query
    let result = test_suite.audit_trail_engine.query(query).await;
    assert!(result.is_ok(), "Audit trail query should succeed");

    let query_result = result.unwrap();
    assert!(
        query_result.execution_time_ms < 5000,
        "Query should complete within 5 seconds"
    );
}

/// Test compliance metrics and monitoring
#[tokio::test]
async fn test_compliance_metrics() {
    let reporting_config = AutomatedReportingConfig::default();

    // Test performance thresholds
    let thresholds = &reporting_config.monitoring_settings.performance_thresholds;
    assert!(
        thresholds.max_generation_time_seconds > 0,
        "Generation time threshold should be positive"
    );
    assert!(
        thresholds.min_success_rate_percentage > 0.0,
        "Success rate threshold should be positive"
    );
    assert!(
        thresholds.min_success_rate_percentage <= 100.0,
        "Success rate threshold should be <= 100%"
    );
}

/// Test regulatory data validation
#[test]
fn test_regulatory_data_validation() {
    let order_execution = create_test_order_execution();

    // Validate required fields
    assert!(
        !order_execution.execution_id.is_empty(),
        "Execution ID is required"
    );
    assert!(!order_execution.symbol.is_empty(), "Symbol is required");
    assert!(
        order_execution.filled_quantity > Decimal::ZERO,
        "Filled quantity must be positive"
    );
    assert!(
        order_execution.execution_price > Decimal::ZERO,
        "Execution price must be positive"
    );
    assert!(!order_execution.currency.is_empty(), "Currency is required");
}

/// Stress test compliance system with high load
#[tokio::test]
async fn test_compliance_high_load() {
    let test_suite = ComplianceTestSuite::new();

    // Generate multiple concurrent compliance assessments
    // Note: We assess sequentially since ComplianceEngine doesn't implement Clone
    // This still tests the engine under repeated load
    let mut success_count = 0;

    for i in 0..100 {
        let context = create_test_compliance_context_with_id(&format!("STRESS-{}", i));
        let result = test_suite
            .compliance_engine
            .assess_compliance(&context)
            .await;

        if result.is_ok() {
            success_count += 1;
        }
    }

    assert!(
        success_count >= 95,
        "At least 95% of assessments should succeed under load"
    );
}

/// Test compliance data encryption and security
#[test]
fn test_compliance_data_security() {
    let audit_config = AuditTrailConfig::default();

    // Verify security settings
    assert!(
        audit_config.encryption_enabled,
        "Encryption should be enabled"
    );
    assert!(
        audit_config.compliance_requirements.immutable_required,
        "Immutability should be required"
    );
    assert!(
        audit_config.compliance_requirements.tamper_detection,
        "Tamper detection should be enabled"
    );
}

// Helper functions for creating test data

fn create_test_compliance_context() -> trading_engine::compliance::ComplianceContext {
    trading_engine::compliance::ComplianceContext {
        order_info: Some(create_test_order_info()),
        client_info: Some(create_test_client_info()),
        market_context: Some(create_test_market_context()),
        timestamp: Utc::now(),
    }
}

fn create_test_compliance_context_with_id(
    id: &str,
) -> trading_engine::compliance::ComplianceContext {
    let mut context = create_test_compliance_context();
    if let Some(order_info) = &mut context.order_info {
        order_info.order_id = OrderId::from(id);
    }
    context
}

fn create_invalid_compliance_context() -> trading_engine::compliance::ComplianceContext {
    trading_engine::compliance::ComplianceContext {
        order_info: None, // Missing required order info
        client_info: None,
        market_context: None,
        timestamp: Utc::now(),
    }
}

fn create_test_order_info() -> OrderInfo {
    OrderInfo {
        order_id: OrderId::from("ORDER-123"),
        side: OrderSide::Buy,
        order_type: OrderType::Limit,
        quantity: Quantity::from_decimal(Decimal::from(100)).unwrap(),
        price: Some(Price::from_decimal(Decimal::from(150))),
        symbol: "AAPL".to_string(),
        client_id: "CLIENT-001".to_string(),
        timestamp: Utc::now(),
    }
}

fn create_test_client_info() -> trading_engine::compliance::ClientInfo {
    trading_engine::compliance::ClientInfo {
        client_id: "CLIENT-001".to_string(),
        classification: trading_engine::compliance::ClientType::Professional,
        risk_tolerance: trading_engine::compliance::RiskTolerance::Moderate,
        jurisdiction: "US".to_string(),
    }
}

fn create_test_market_context() -> trading_engine::compliance::MarketContext {
    trading_engine::compliance::MarketContext {
        conditions: trading_engine::compliance::MarketConditions::Normal,
        session: trading_engine::compliance::TradingSession::Regular,
        volatility: 0.15,
    }
}

fn create_test_order_execution() -> OrderExecution {
    OrderExecution {
        execution_id: "EXEC-123".to_string(),
        order_id: "ORDER-123".to_string(),
        symbol: "AAPL".to_string(),
        isin: Some("US0378331005".to_string()),
        venue: "NYSE".to_string(),
        execution_time: Utc::now(),
        execution_price: Decimal::from(150),
        filled_quantity: Decimal::from(100),
        currency: "USD".to_string(),
        order_type: "LIMIT".to_string(),
        side: "BUY".to_string(),
    }
}

fn create_test_order_details() -> OrderDetails {
    OrderDetails {
        transaction_id: "TXN-123".to_string(),
        user_id: "user_123".to_string(),
        session_id: Some("session_456".to_string()),
        client_ip: Some("192.168.1.100".to_string()),
        symbol: "AAPL".to_string(),
        quantity: Decimal::from(100),
        price: Some(Decimal::from(150)),
        side: "BUY".to_string(),
        order_type: "LIMIT".to_string(),
        venue: Some("NYSE".to_string()),
        account_id: "ACC-123".to_string(),
        strategy_id: Some("STRAT-001".to_string()),
        metadata: HashMap::new(),
    }
}

fn create_test_execution_details() -> ExecutionDetails {
    ExecutionDetails {
        transaction_id: "TXN-123".to_string(),
        order_id: "ORDER-123".to_string(),
        symbol: "AAPL".to_string(),
        executed_quantity: Decimal::from(100),
        execution_price: Decimal::from(150),
        side: "BUY".to_string(),
        venue: "NYSE".to_string(),
        account_id: "ACC-123".to_string(),
        strategy_id: Some("STRAT-001".to_string()),
        metadata: HashMap::new(),
        processing_latency_ns: 50_000, // 50 microseconds
        queue_time_ns: 10_000,         // 10 microseconds
        system_load: 0.75,
        memory_usage_bytes: 1_048_576, // 1 MB
    }
}

/// Integration test that combines all compliance components
#[tokio::test]
async fn test_full_compliance_integration() {
    let test_suite = ComplianceTestSuite::new();

    // 1. Log order creation
    let order_details = create_test_order_details();
    let audit_result = test_suite
        .audit_trail_engine
        .log_order_created("ORDER-INTEGRATION", &order_details);
    assert!(audit_result.is_ok(), "Order audit logging should succeed");

    // 2. Assess compliance
    let context = create_test_compliance_context();
    let compliance_result = test_suite
        .compliance_engine
        .assess_compliance(&context)
        .await;
    assert!(
        compliance_result.is_ok(),
        "Compliance assessment should succeed"
    );

    // 3. Generate transaction report
    let execution = create_test_order_execution();
    let report_result = test_suite
        .transaction_reporter
        .generate_transaction_report(&execution)
        .await;
    assert!(
        report_result.is_ok(),
        "Transaction report generation should succeed"
    );

    // 4. Log execution
    let execution_details = create_test_execution_details();
    let execution_audit_result = test_suite
        .audit_trail_engine
        .log_order_executed(&execution_details);
    assert!(
        execution_audit_result.is_ok(),
        "Execution audit logging should succeed"
    );

    // 5. Verify overall compliance
    let final_compliance = compliance_result.unwrap();
    assert!(
        final_compliance.compliance_score > 80.0,
        "Overall compliance score should be high after successful operations"
    );
}

/// Performance test for audit trail logging
#[tokio::test]
async fn test_audit_trail_performance() {
    let audit_config = AuditTrailConfig::default();
    let audit_engine = AuditTrailEngine::new(audit_config);

    let start_time = std::time::Instant::now();

    // Log 1000 events rapidly
    for i in 0..1000 {
        let order_details = OrderDetails {
            transaction_id: format!("PERF-TXN-{}", i),
            user_id: "perf_user".to_string(),
            session_id: Some("perf_session".to_string()),
            client_ip: Some("127.0.0.1".to_string()),
            symbol: "AAPL".to_string(),
            quantity: Decimal::from(100),
            price: Some(Decimal::from(150)),
            side: "BUY".to_string(),
            order_type: "LIMIT".to_string(),
            venue: Some("NYSE".to_string()),
            account_id: "PERF-ACC".to_string(),
            strategy_id: Some("PERF-STRAT".to_string()),
            metadata: HashMap::new(),
        };

        let result = audit_engine.log_order_created(&format!("PERF-ORDER-{}", i), &order_details);
        assert!(result.is_ok(), "Performance test logging should succeed");
    }

    let elapsed = start_time.elapsed();

    // Should be able to log 1000 events in under 100ms for HFT performance
    assert!(
        elapsed.as_millis() < 100,
        "Should log 1000 events in under 100ms, took {}ms",
        elapsed.as_millis()
    );
}
