//! Memory bandwidth measurement

use std::time::Instant;

use super::super::error::ProfilingError;

/// Memory bandwidth result
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct MemoryBandwidthResult {
    pub read_bandwidth_gbps: f64,
    pub write_bandwidth_gbps: f64,
    pub copy_bandwidth_gbps: f64,
    pub buffer_size_bytes: u64,
    pub iterations: u32,
}

/// Measure memory bandwidth (read, write, copy)
/// Uses optimized memory operations to achieve realistic bandwidth measurements.
pub fn measure_memory_bandwidth() -> Result<MemoryBandwidthResult, ProfilingError> {
    measure_memory_bandwidth_with_params(64, 5)
}

/// Measure memory bandwidth with custom buffer size and iterations
///
/// # Arguments
/// * `size_mb` - Buffer size in MB
/// * `iterations` - Number of iterations to run
pub fn measure_memory_bandwidth_with_params(
    size_mb: u64,
    iterations: u32,
) -> Result<MemoryBandwidthResult, ProfilingError> {
    super::super::logging::log_info(&format!(
        "Measuring memory bandwidth: {}MB buffer, {} iterations",
        size_mb, iterations
    ));

    let buffer_size = (size_mb * 1024 * 1024) as usize;
    let iterations = iterations as usize;

    let mut buffer: Vec<u64> = vec![0u64; buffer_size / 8];
    let mut buffer2: Vec<u64> = vec![0u64; buffer_size / 8];

    // Warm up caches
    for (i, elem) in buffer.iter_mut().enumerate() {
        *elem = i as u64;
    }
    buffer2.copy_from_slice(&buffer);

    // Measure read bandwidth - use chunks for better vectorization
    let start = Instant::now();
    for _ in 0..iterations {
        let sum: u64 = buffer
            .chunks(1024)
            .map(|chunk| chunk.iter().copied().sum::<u64>())
            .sum();
        std::hint::black_box(sum);
    }
    let read_duration = start.elapsed();
    let total_bytes = (buffer_size * iterations) as f64;
    let read_bandwidth_gbps = total_bytes / read_duration.as_secs_f64() / 1_000_000_000.0;

    // Measure write bandwidth - use slice fill for better optimization
    let start = Instant::now();
    for iter in 0..iterations {
        let value = iter as u64;
        buffer.fill(value);
        std::hint::black_box(&buffer);
    }
    let write_duration = start.elapsed();
    let write_bandwidth_gbps = total_bytes / write_duration.as_secs_f64() / 1_000_000_000.0;

    // Measure copy bandwidth using optimized copy_from_slice
    let start = Instant::now();
    for _ in 0..iterations {
        buffer2.copy_from_slice(&buffer);
        std::hint::black_box(&buffer2);
    }
    let copy_duration = start.elapsed();
    let copy_bandwidth_gbps = total_bytes / copy_duration.as_secs_f64() / 1_000_000_000.0;

    Ok(MemoryBandwidthResult {
        read_bandwidth_gbps,
        write_bandwidth_gbps,
        copy_bandwidth_gbps,
        buffer_size_bytes: buffer_size as u64,
        iterations: iterations as u32,
    })
}
