//! Network profiling core tests

use super::{
    BandwidthResult,
    bandwidth::{measure_bandwidth, measure_bandwidth_download, measure_bandwidth_upload},
    jitter::run_jitter_test,
    latency::measure_latency,
    throughput::test_udp_throughput,
};
use std::time::Duration;

#[test]
fn test_measure_bandwidth_upload() {
    // Test upload bandwidth measurement
    let server = "127.0.0.1";
    let duration = Duration::from_secs(1);

    // This test will likely fail if iperf3 is not available or no server is running
    // That's expected behavior for unit tests
    let result = measure_bandwidth_upload(server, duration);

    match result {
        Ok(bandwidth) => {
            // Verify the result structure
            assert!(
                bandwidth.upload_bps >= 0.0,
                "Upload bandwidth should be non-negative"
            );
            assert_eq!(
                bandwidth.download_bps, 0.0,
                "Download should be 0 for upload-only test"
            );
            assert_eq!(bandwidth.server, server, "Server should match input");
            assert_eq!(bandwidth.duration, duration, "Duration should match input");
        }
        Err(_) => {
            // Expected if iperf3 is not available or server not running
            // This is acceptable for unit tests
        }
    }
}

#[test]
fn test_measure_bandwidth_download() {
    // Test download bandwidth measurement
    let server = "127.0.0.1";
    let duration = Duration::from_secs(1);

    // This test will likely fail if iperf3 is not available or no server is running
    // That's expected behavior for unit tests
    let result = measure_bandwidth_download(server, duration);

    match result {
        Ok(bandwidth) => {
            // Verify the result structure
            assert!(
                bandwidth.download_bps >= 0.0,
                "Download bandwidth should be non-negative"
            );
            assert_eq!(
                bandwidth.upload_bps, 0.0,
                "Upload should be 0 for download-only test"
            );
            assert_eq!(bandwidth.server, server, "Server should match input");
            assert_eq!(bandwidth.duration, duration, "Duration should match input");
        }
        Err(_) => {
            // Expected if iperf3 is not available or server not running
            // This is acceptable for unit tests
        }
    }
}

#[test]
fn test_measure_bandwidth_combined() {
    // Test combined bandwidth measurement (for comparison)
    let server = "127.0.0.1";
    let duration = Duration::from_secs(1);

    // This test will likely fail if iperf3 is not available or no server is running
    // That's expected behavior for unit tests
    let result = measure_bandwidth(server, duration);

    match result {
        Ok(bandwidth) => {
            // Verify the result structure
            assert!(
                bandwidth.upload_bps >= 0.0,
                "Upload bandwidth should be non-negative"
            );
            assert!(
                bandwidth.download_bps >= 0.0,
                "Download bandwidth should be non-negative"
            );
            assert_eq!(bandwidth.server, server, "Server should match input");
            assert_eq!(bandwidth.duration, duration, "Duration should match input");
        }
        Err(_) => {
            // Expected if iperf3 is not available or server not running
            // This is acceptable for unit tests
        }
    }
}

#[test]
fn test_measure_latency() {
    // Test latency measurement
    let host = "127.0.0.1";
    let count = 10;

    // This test may fail if network is not available
    let result = measure_latency(host, count);

    match result {
        Ok(latency) => {
            // Verify the result structure
            assert!(latency.min_ms >= 0.0, "Min latency should be non-negative");
            assert!(latency.max_ms >= latency.min_ms, "Max should be >= min");
            assert!(latency.avg_ms >= latency.min_ms, "Avg should be >= min");
            assert!(latency.avg_ms <= latency.max_ms, "Avg should be <= max");
            assert!(
                latency.packet_loss_percent >= 0.0,
                "Packet loss should be non-negative"
            );
            assert!(
                latency.packet_loss_percent <= 100.0,
                "Packet loss should be <= 100%"
            );
        }
        Err(_) => {
            // Expected if network is not available
            // This is acceptable for unit tests
        }
    }
}

#[test]
fn test_run_jitter_test() {
    // Test jitter measurement
    let server = "127.0.0.1";

    // This test will likely fail if iperf3 is not available or no server is running
    // That's expected behavior for unit tests
    let result = run_jitter_test(server);

    match result {
        Ok(jitter) => {
            // Verify the result structure
            assert!(jitter.jitter_ms >= 0.0, "Jitter should be non-negative");
            assert!(
                jitter.min_latency_ms >= 0.0,
                "Min latency should be non-negative"
            );
            assert!(
                jitter.max_latency_ms >= jitter.min_latency_ms,
                "Max should be >= min"
            );
        }
        Err(_) => {
            // Expected if iperf3 is not available or server not running
            // This is acceptable for unit tests
        }
    }
}

#[test]
fn test_udp_throughput_function() {
    // Test UDP throughput measurement
    let server = "127.0.0.1";
    let bandwidth = 1_000_000; // 1 Mbps

    // This test will likely fail if iperf3 is not available or no server is running
    // That's expected behavior for unit tests
    let result = test_udp_throughput(server, bandwidth);

    match result {
        Ok(throughput) => {
            // Verify the result structure
            assert!(
                throughput.actual_bandwidth_bps >= 0.0,
                "Actual bandwidth should be non-negative"
            );
            assert!(
                throughput.packet_loss_percent >= 0.0,
                "Packet loss should be non-negative"
            );
            assert!(
                throughput.packet_loss_percent <= 100.0,
                "Packet loss should be <= 100%"
            );
        }
        Err(_) => {
            // Expected if iperf3 is not available or server not running
            // This is acceptable for unit tests
        }
    }
}

#[test]
fn test_bandwidth_result_consistency() {
    // Test that BandwidthResult is consistent
    let result = BandwidthResult {
        upload_bps: 1_000_000.0,
        download_bps: 2_000_000.0,
        server: "test.server".to_string(),
        duration: Duration::from_secs(10),
    };

    assert_eq!(result.upload_bps, 1_000_000.0);
    assert_eq!(result.download_bps, 2_000_000.0);
    assert_eq!(result.server, "test.server");
    assert_eq!(result.duration, Duration::from_secs(10));
}

#[test]
fn test_bandwidth_result_default() {
    // Test default values
    let result = BandwidthResult::default();

    assert_eq!(result.upload_bps, 0.0);
    assert_eq!(result.download_bps, 0.0);
    assert_eq!(result.server, "unknown");
    assert_eq!(result.duration, Duration::from_secs(0));
}

#[test]
fn test_network_function_parameters() {
    // Test that network functions handle edge cases properly

    // Test with very short duration
    let server = "127.0.0.1";
    let duration = Duration::from_millis(100);

    let result = measure_bandwidth_upload(server, duration);
    match result {
        Ok(_) => {
            // Should work with short duration
        }
        Err(_) => {
            // Expected if iperf3 not available
        }
    }

    // Test with invalid server (should fail gracefully)
    let invalid_server = "invalid.server.name";
    let result = measure_latency(invalid_server, 5);
    assert!(result.is_err(), "Should fail with invalid server name");
}

#[test]
fn test_network_function_error_handling() {
    // Test that network functions handle errors gracefully

    // Test with empty server
    let result = measure_bandwidth("", Duration::from_secs(1));
    assert!(result.is_err(), "Should fail with empty server");

    // Test with zero duration
    let result = measure_latency("127.0.0.1", 0);
    match result {
        Ok(_) => {
            // Some implementations might handle zero count
        }
        Err(_) => {
            // Others might reject zero count
        }
    }

    // Test with very large count (should be clamped)
    let result = measure_latency("127.0.0.1", 1000);
    match result {
        Ok(_) => {
            // Should handle large count by clamping
        }
        Err(_) => {
            // Or might reject very large count
        }
    }
}
