//! Comprehensive coverage tests for data crate
//!
//! This test suite targets uncovered error paths, edge cases, and validation logic
//! to improve overall test coverage toward 95%
#![allow(
    clippy::absurd_extreme_comparisons,
    clippy::assertions_on_constants,
    clippy::assertions_on_result_states,
    clippy::clone_on_copy,
    clippy::decimal_literal_representation,
    clippy::doc_lazy_continuation,
    clippy::doc_markdown,
    clippy::double_comparisons,
    clippy::else_if_without_else,
    clippy::empty_drop,
    clippy::expect_used,
    clippy::field_reassign_with_default,
    clippy::format_push_string,
    clippy::if_then_some_else_none,
    clippy::indexing_slicing,
    clippy::integer_division,
    clippy::len_zero,
    clippy::let_and_return,
    clippy::let_underscore_must_use,
    clippy::manual_let_else,
    clippy::manual_range_contains,
    clippy::map_err_ignore,
    clippy::missing_const_for_fn,
    clippy::modulo_arithmetic,
    clippy::needless_range_loop,
    clippy::new_without_default,
    clippy::non_ascii_literal,
    clippy::nonminimal_bool,
    clippy::octal_escapes,
    clippy::overly_complex_bool_expr,
    clippy::redundant_clone,
    clippy::shadow_reuse,
    clippy::shadow_unrelated,
    clippy::similar_names,
    clippy::single_component_path_imports,
    clippy::single_match_else,
    clippy::str_to_string,
    clippy::string_slice,
    clippy::tests_outside_test_module,
    clippy::unnecessary_cast,
    clippy::unnecessary_get_then_check,
    clippy::unnecessary_unwrap,
    clippy::unseparated_literal_suffix,
    clippy::unwrap_or_default,
    clippy::unwrap_used,
    clippy::use_debug,
    clippy::useless_vec,
    clippy::wildcard_enum_match_arm,
    dead_code,
    deprecated,
    unreachable_pub,
    unused_assignments,
    unused_comparisons,
    unused_imports,
    unused_variables
)]

use chrono::Utc;
use config::data_config::{
    DataCompressionAlgorithm, DataStorageConfig, DataStorageFormat, DataValidationConfig,
    MissingDataHandling, OutlierDetectionMethod,
};
use data::error::{DataError, ErrorSeverity};
// Import ConnectionState from traits module which is re-exported at providers level
use data::providers::ConnectionState;
use data::storage::StorageManager;
use data::validation::{
    DataValidator, ErrorSeverity as ValidationErrorSeverity, ValidationError, ValidationErrorType,
    ValidationWarning, ValidationWarningType,
};
use std::collections::HashMap;

// ============================================================================
// Error Module Tests - Testing Error Path Coverage
// ============================================================================

#[test]
fn test_error_helper_methods() {
    // Test all error creation helper methods
    let net_err = DataError::network("Connection refused");
    assert!(matches!(net_err, DataError::Network { .. }));
    assert_eq!(net_err.category(), "NETWORK");

    let fix_err = DataError::fix_protocol("Invalid FIX message");
    assert!(matches!(fix_err, DataError::FixProtocol { .. }));
    assert_eq!(fix_err.category(), "FIX_PROTOCOL");

    let auth_err = DataError::authentication("Invalid credentials");
    assert!(matches!(auth_err, DataError::Authentication { .. }));
    assert_eq!(auth_err.severity(), ErrorSeverity::Critical);

    let msg_err = DataError::message_parsing("Malformed message");
    assert!(matches!(msg_err, DataError::MessageParsing { .. }));

    let session_err = DataError::session("Session expired");
    assert!(matches!(session_err, DataError::Session { .. }));

    let order_err = DataError::order("Order rejected");
    assert!(matches!(order_err, DataError::Order { .. }));
    assert_eq!(order_err.severity(), ErrorSeverity::High);

    let internal_err = DataError::internal("Internal failure");
    assert!(matches!(internal_err, DataError::Broker { .. }));
}

#[test]
fn test_error_conversion_edge_cases() {
    // Test edge cases in error conversions
    let empty_config_err = DataError::configuration("", "Missing field");
    assert!(matches!(empty_config_err, DataError::Configuration { .. }));

    let long_message = "a".repeat(1000);
    let long_err = DataError::network(&long_message);
    assert!(format!("{}", long_err).contains(&long_message));
}

#[test]
fn test_error_retryability_comprehensive() {
    // Comprehensive retryability testing
    assert!(DataError::Connection("test".to_string()).is_retryable());
    assert!(DataError::RateLimit.is_retryable());

    // Non-retryable errors
    assert!(!DataError::Compression("test".to_string()).is_retryable());
    assert!(!DataError::InvalidFormat("test".to_string()).is_retryable());
    assert!(!DataError::Conversion("test".to_string()).is_retryable());
    assert!(!DataError::Unsupported("test".to_string()).is_retryable());
    assert!(!DataError::NotImplemented("test".to_string()).is_retryable());
}

#[test]
fn test_error_severity_ordering() {
    // Test severity level ordering
    assert!(ErrorSeverity::Critical > ErrorSeverity::High);
    assert!(ErrorSeverity::High > ErrorSeverity::Medium);
    assert!(ErrorSeverity::Medium > ErrorSeverity::Low);

    // Test severity for various errors
    assert_eq!(
        DataError::FixProtocol {
            message: "test".to_string()
        }
        .severity(),
        ErrorSeverity::High
    );
    assert_eq!(
        DataError::NotFound("test".to_string()).severity(),
        ErrorSeverity::Medium
    );
}

#[test]
fn test_error_categories_comprehensive() {
    // Test all error category mappings
    assert_eq!(
        DataError::Unsupported("test".to_string()).category(),
        "UNSUPPORTED"
    );
    assert_eq!(
        DataError::NotImplemented("test".to_string()).category(),
        "NOT_IMPLEMENTED"
    );
    assert_eq!(
        DataError::Initialization("test".to_string()).category(),
        "INITIALIZATION"
    );
    assert_eq!(
        DataError::InvalidFormat("test".to_string()).category(),
        "INVALID_FORMAT"
    );
    assert_eq!(
        DataError::Conversion("test".to_string()).category(),
        "CONVERSION"
    );
    assert_eq!(
        DataError::InvalidParameter {
            field: "test".to_string(),
            message: "test".to_string()
        }
        .category(),
        "INVALID_PARAMETER"
    );
}

#[test]
fn test_error_api_variants() {
    // Test API error with and without status code
    let api_with_status = DataError::api("Rate limited", Some("429"));
    assert!(matches!(api_with_status, DataError::Api { .. }));

    let api_no_status = DataError::api("Unknown error", None::<String>);
    assert!(matches!(api_no_status, DataError::Api { .. }));
}

#[test]
fn test_error_subscription_helper() {
    let sub_err = DataError::subscription("Symbol not available");
    assert!(matches!(sub_err, DataError::Subscription { .. }));
    assert_eq!(sub_err.category(), "SUBSCRIPTION");
}

// ============================================================================
// Storage Module Tests - Edge Cases and Error Paths
// ============================================================================

#[tokio::test]
async fn test_storage_initialization_with_invalid_path() {
    let config = DataStorageConfig {
        format: DataStorageFormat::Parquet,
        compression: config::data_config::DataCompressionConfig {
            enabled: false,
            algorithm: DataCompressionAlgorithm::ZSTD,
            level: Some(3),
        },
        path: "/invalid/nonexistent/path/with/no/permissions".to_string(),
        base_directory: std::path::PathBuf::from("/invalid/nonexistent/path/with/no/permissions"),
        partition_by: vec![],
        versioning: config::data_config::DataVersioningConfig {
            enabled: false,
            version_format: "v%Y%m%d_%H%M%S".to_string(),
            keep_versions: 5,
        },
        retention: config::data_config::DataRetentionConfig::default(),
    };

    // This should fail gracefully
    let result = StorageManager::new(config).await;
    // We expect this to fail on most systems
    if let Err(err) = result {
        assert!(matches!(err, DataError::Io(_)));
    }
}

#[tokio::test]
async fn test_storage_with_empty_base_directory() {
    let temp_dir = std::env::temp_dir().join("foxhunt_test_empty");
    let _ = std::fs::remove_dir_all(&temp_dir); // Clean up if exists

    let config = DataStorageConfig {
        format: DataStorageFormat::Parquet,
        compression: config::data_config::DataCompressionConfig {
            enabled: true,
            algorithm: DataCompressionAlgorithm::ZSTD,
            level: Some(3),
        },
        path: temp_dir.to_string_lossy().to_string(),
        base_directory: temp_dir.clone(),
        partition_by: vec![],
        versioning: config::data_config::DataVersioningConfig {
            enabled: true,
            version_format: "v%Y%m%d_%H%M%S".to_string(),
            keep_versions: 5,
        },
        retention: config::data_config::DataRetentionConfig::default(),
    };

    let storage = StorageManager::new(config).await;
    assert!(storage.is_ok());

    // Cleanup
    let _ = std::fs::remove_dir_all(&temp_dir);
}

#[tokio::test]
async fn test_storage_compression_edge_cases() {
    let temp_dir = std::env::temp_dir().join("foxhunt_test_compression");
    let _ = std::fs::remove_dir_all(&temp_dir);

    let config = DataStorageConfig {
        format: DataStorageFormat::Parquet,
        compression: config::data_config::DataCompressionConfig {
            enabled: true,
            algorithm: DataCompressionAlgorithm::ZSTD,
            level: Some(22), // Maximum compression level
        },
        path: temp_dir.to_string_lossy().to_string(),
        base_directory: temp_dir.clone(),
        partition_by: vec![],
        versioning: config::data_config::DataVersioningConfig {
            enabled: false,
            version_format: "v%Y%m%d_%H%M%S".to_string(),
            keep_versions: 1,
        },
        retention: config::data_config::DataRetentionConfig::default(),
    };

    let storage = StorageManager::new(config).await;
    assert!(storage.is_ok());

    // Cleanup
    let _ = std::fs::remove_dir_all(&temp_dir);
}

// ============================================================================
// Validation Module Tests - Comprehensive Edge Cases
// ============================================================================

#[test]
fn test_validation_error_severity_levels() {
    let _low = ValidationErrorSeverity::Low;
    let _medium = ValidationErrorSeverity::Medium;
    let high = ValidationErrorSeverity::High;
    let critical = ValidationErrorSeverity::Critical;

    // Test ordering (if PartialOrd is implemented)
    assert!(format!("{:?}", critical).contains("Critical"));
    assert!(format!("{:?}", high).contains("High"));
}

#[test]
fn test_validation_error_types() {
    let error_types = vec![
        ValidationErrorType::PriceOutlier,
        ValidationErrorType::VolumeOutlier,
        ValidationErrorType::InvalidPrice,
        ValidationErrorType::InvalidVolume,
        ValidationErrorType::TimestampGap,
        ValidationErrorType::TimestampDrift,
        ValidationErrorType::DuplicateRecord,
        ValidationErrorType::MissingField,
        ValidationErrorType::InvalidFormat,
        ValidationErrorType::BusinessLogicViolation,
        ValidationErrorType::ConsistencyViolation,
    ];

    // Ensure all variants are covered
    for error_type in error_types {
        let debug_str = format!("{:?}", error_type);
        assert!(!debug_str.is_empty());
    }
}

#[test]
fn test_validation_warning_types() {
    let warning_types = vec![
        ValidationWarningType::UnusualVolume,
        ValidationWarningType::UnusualPrice,
        ValidationWarningType::HighVolatility,
        ValidationWarningType::LowLiquidity,
        ValidationWarningType::StaleTrade,
        ValidationWarningType::WideBidAsk,
        ValidationWarningType::InfrequentUpdates,
    ];

    // Ensure all variants are covered
    for warning_type in warning_types {
        let debug_str = format!("{:?}", warning_type);
        assert!(!debug_str.is_empty());
    }
}

#[tokio::test]
async fn test_validation_config_edge_cases() {
    // Test validation with extreme config values
    let config = DataValidationConfig {
        enable_price_validation: true,
        enable_volume_validation: true,
        price_threshold: 0.0,
        volume_threshold: 0.0,
        outlier_method: OutlierDetectionMethod::ZScore,
        max_price_change: f64::MAX,
        max_volume_change: f64::MAX,
        max_timestamp_drift: 0, // Zero gap
        price_validation: true,
        volume_validation: true,
        timestamp_validation: true,
        outlier_detection: true,
        missing_data_handling: MissingDataHandling::Skip,
    };

    let validator = DataValidator::new(config);
    assert!(validator.is_ok());
}

#[test]
fn test_validation_error_with_none_fields() {
    let error = ValidationError {
        error_type: ValidationErrorType::MissingField,
        message: "Field is missing".to_string(),
        field: None, // Test None case
        value: None, // Test None case
        timestamp: Utc::now(),
        severity: ValidationErrorSeverity::High,
    };

    assert!(error.field.is_none());
    assert!(error.value.is_none());
}

#[test]
fn test_validation_warning_with_none_field() {
    let warning = ValidationWarning {
        warning_type: ValidationWarningType::UnusualVolume,
        message: "Volume spike detected".to_string(),
        field: None, // Test None case
        timestamp: Utc::now(),
    };

    assert!(warning.field.is_none());
}

// ============================================================================
// Provider Common Tests - Connection State and Metrics
// ============================================================================

#[test]
fn test_connection_state_transitions() {
    // Test all connection states
    let states = vec![
        ConnectionState::Disconnected,
        ConnectionState::Connecting,
        ConnectionState::Connected,
        ConnectionState::Reconnecting,
        ConnectionState::Failed,
    ];

    for state in states {
        let debug_str = format!("{:?}", state);
        assert!(!debug_str.is_empty());
    }
}

// TODO: ProviderMetrics has been removed from the API - needs rewrite for new ConnectionStatus
// #[test]
// fn test_provider_metrics_initialization() {
//     let metrics = ProviderMetrics {
//         messages_received: 0,
//         messages_sent: 0,
//         errors_count: 0,
//         reconnections: 0,
//         last_heartbeat: None,
//         uptime_seconds: 0,
//     };
//
//     assert_eq!(metrics.messages_received, 0);
//     assert!(metrics.last_heartbeat.is_none());
// }

// TODO: ProviderMetrics has been removed from the API - needs rewrite for new ConnectionStatus
// #[test]
// fn test_provider_metrics_edge_values() {
//     let metrics = ProviderMetrics {
//         messages_received: u64::MAX,
//         messages_sent: u64::MAX,
//         errors_count: u64::MAX,
//         reconnections: u64::MAX,
//         last_heartbeat: Some(Utc::now()),
//         uptime_seconds: u64::MAX,
//     };
//
//     assert_eq!(metrics.messages_received, u64::MAX);
//     assert_eq!(metrics.uptime_seconds, u64::MAX);
// }

// ============================================================================
// Utils Module Tests - Edge Cases
// ============================================================================

#[test]
fn test_utils_checksum_validation_empty() {
    // Test checksum validation with empty data
    use sha2::Digest;
    let data: Vec<u8> = vec![];
    let checksum = sha2::Sha256::digest(&data);
    let checksum_hex = format!("{:x}", checksum);
    assert_eq!(checksum_hex.len(), 64); // SHA-256 produces 64 hex chars
}

#[test]
fn test_utils_checksum_validation_large() {
    // Test checksum validation with large data
    use sha2::Digest;
    let data: Vec<u8> = vec![0xFF; 1_000_000]; // 1MB of data
    let checksum = sha2::Sha256::digest(&data);
    let checksum_hex = format!("{:x}", checksum);
    assert_eq!(checksum_hex.len(), 64);
}

// ============================================================================
// Data Type Tests - Edge Cases
// ============================================================================

#[test]
fn test_data_types_serialization_edge_cases() {
    use serde_json;

    // Test serialization of various data structures
    let mut tags: HashMap<String, String> = HashMap::new();
    tags.insert("key".to_string(), "value".to_string());
    tags.insert("empty".to_string(), "".to_string());
    tags.insert("unicode".to_string(), "🦀".to_string());

    let json = serde_json::to_string(&tags).unwrap();
    assert!(json.contains("key"));
    assert!(json.contains("empty"));
    assert!(json.contains("unicode"));
}

// ============================================================================
// Integration Tests - Error Recovery
// ============================================================================

#[tokio::test]
async fn test_error_recovery_pattern() {
    // Test error recovery pattern with retryable errors
    let mut attempt = 0;
    let max_attempts = 3;

    let result = loop {
        attempt += 1;
        let err = DataError::network("Temporary failure");

        if err.is_retryable() && attempt < max_attempts {
            continue;
        }

        break if attempt < max_attempts {
            Ok(())
        } else {
            Err(err)
        };
    };

    assert!(result.is_err());
}

#[test]
fn test_error_chaining() {
    // Test error chaining with From trait
    let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "Access denied");
    let data_err: DataError = io_err.into();

    assert!(matches!(data_err, DataError::Io(_)));
    assert!(data_err.is_retryable());
}

// ============================================================================
// Boundary Value Tests
// ============================================================================

#[test]
fn test_compression_level_boundaries() {
    // Test compression level boundaries
    let algorithms = vec![
        DataCompressionAlgorithm::ZSTD,
        DataCompressionAlgorithm::LZ4,
        DataCompressionAlgorithm::GZIP,
        DataCompressionAlgorithm::None,
    ];

    for algo in algorithms {
        let debug_str = format!("{:?}", algo);
        assert!(!debug_str.is_empty());
    }
}

#[test]
fn test_storage_format_variants() {
    let formats = vec![
        DataStorageFormat::Parquet,
        DataStorageFormat::Arrow,
        DataStorageFormat::Json,
        DataStorageFormat::Csv,
    ];

    for format in formats {
        let debug_str = format!("{:?}", format);
        assert!(!debug_str.is_empty());
    }
}

// ============================================================================
// Concurrency Tests
// ============================================================================

#[tokio::test]
async fn test_concurrent_error_creation() {
    use tokio::task;

    let handles: Vec<_> = (0..10)
        .map(|i| task::spawn(async move { DataError::network(format!("Error {}", i)) }))
        .collect();

    for handle in handles {
        let err = handle.await.unwrap();
        assert!(matches!(err, DataError::Network { .. }));
    }
}

#[test]
fn test_validation_error_serialization() {
    use serde_json;

    let error = ValidationError {
        error_type: ValidationErrorType::PriceOutlier,
        message: "Price exceeds threshold".to_string(),
        field: Some("price".to_string()),
        value: Some("999.99".to_string()),
        timestamp: Utc::now(),
        severity: ValidationErrorSeverity::High,
    };

    let json = serde_json::to_string(&error).unwrap();
    let deserialized: ValidationError = serde_json::from_str(&json).unwrap();

    assert_eq!(error.message, deserialized.message);
    assert_eq!(error.field, deserialized.field);
}

// ============================================================================
// Performance and Stress Tests
// ============================================================================

#[test]
fn test_large_error_message() {
    let large_message = "x".repeat(10_000);
    let err = DataError::network(&large_message);
    let display = format!("{}", err);
    assert!(display.len() > 10_000);
}

#[test]
fn test_many_tags() {
    let mut tags: HashMap<String, String> = HashMap::new();
    for i in 0..1000 {
        tags.insert(format!("key{}", i), format!("value{}", i));
    }
    assert_eq!(tags.len(), 1000);
}

// ============================================================================
// Null and Empty Tests
// ============================================================================

#[test]
fn test_empty_string_errors() {
    let err = DataError::network("");
    assert!(matches!(err, DataError::Network { .. }));

    let err = DataError::configuration("", "");
    assert!(matches!(err, DataError::Configuration { .. }));
}

// TODO: ProviderMetrics has been removed from the API - needs rewrite for new ConnectionStatus
// #[test]
// fn test_zero_values() {
//     let metrics = ProviderMetrics {
//         messages_received: 0,
//         messages_sent: 0,
//         errors_count: 0,
//         reconnections: 0,
//         last_heartbeat: None,
//         uptime_seconds: 0,
//     };
//
//     assert_eq!(metrics.messages_received, 0);
//     assert_eq!(metrics.uptime_seconds, 0);
// }
