//! Bandwidth measurement

use std::time::Duration;

use super::super::error::ProfilingError;
use super::iperf::{IperfClient, IperfConfig};
use super::protocol::Protocol;

/// Bandwidth measurement result
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct BandwidthResult {
    pub upload_bps: f64,
    pub download_bps: f64,
    pub server: String,
    pub duration: Duration,
}

impl Default for BandwidthResult {
    fn default() -> Self {
        Self {
            upload_bps: 0.0,
            download_bps: 0.0,
            server: "unknown".to_string(),
            duration: Duration::from_secs(0),
        }
    }
}

/// Measure bandwidth to server (upload and download)
pub fn measure_bandwidth(
    server: &str,
    duration: Duration,
) -> Result<BandwidthResult, ProfilingError> {
    let client = IperfClient::new(server)?;

    let upload_config = IperfConfig::new()
        .with_server(server)
        .with_duration(duration)
        .with_protocol(Protocol::Tcp)
        .with_reverse(false);

    let download_config = IperfConfig::new()
        .with_server(server)
        .with_duration(duration)
        .with_protocol(Protocol::Tcp)
        .with_reverse(true);

    super::super::logging::log_info(&format!("Measuring upload bandwidth to {}", server));
    let upload_result = client.run_iperf_test(&upload_config)?;

    super::super::logging::log_info(&format!("Measuring download bandwidth from {}", server));
    let download_result = client.run_iperf_test(&download_config)?;

    Ok(BandwidthResult {
        upload_bps: upload_result.bandwidth_bps,
        download_bps: download_result.bandwidth_bps,
        server: server.to_string(),
        duration,
    })
}

/// Measure upload bandwidth to server
pub fn measure_bandwidth_upload(
    server: &str,
    duration: Duration,
) -> Result<BandwidthResult, ProfilingError> {
    let client = IperfClient::new(server)?;

    let config = IperfConfig::new()
        .with_server(server)
        .with_duration(duration)
        .with_protocol(Protocol::Tcp)
        .with_reverse(false);

    super::super::logging::log_info(&format!("Measuring upload bandwidth to {}", server));
    let result = client.run_iperf_test(&config)?;

    Ok(BandwidthResult {
        upload_bps: result.bandwidth_bps,
        download_bps: 0.0, // Not measured in upload-only test
        server: server.to_string(),
        duration,
    })
}

/// Measure download bandwidth from server
pub fn measure_bandwidth_download(
    server: &str,
    duration: Duration,
) -> Result<BandwidthResult, ProfilingError> {
    let client = IperfClient::new(server)?;

    let config = IperfConfig::new()
        .with_server(server)
        .with_duration(duration)
        .with_protocol(Protocol::Tcp)
        .with_reverse(true);

    super::super::logging::log_info(&format!("Measuring download bandwidth from {}", server));
    let result = client.run_iperf_test(&config)?;

    Ok(BandwidthResult {
        upload_bps: 0.0, // Not measured in download-only test
        download_bps: result.bandwidth_bps,
        server: server.to_string(),
        duration,
    })
}
