//! Sequential I/O benchmark

use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::path::Path;
use std::time::Instant;

use super::super::error::ProfilingError;
use super::super::tempfile::TempFileManager;
use super::super::validation::validate_disk_space;

/// Sequential I/O result
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct SequentialResult {
    pub throughput_mbps: f64,
    pub total_bytes: u64,
    pub duration: std::time::Duration,
}

/// Measure sequential read performance
pub fn measure_sequential_read(
    path: &Path,
    size_bytes: u64,
) -> Result<SequentialResult, ProfilingError> {
    super::super::logging::log_info(&format!("Measuring sequential read: {} bytes", size_bytes));

    // Validate disk space before benchmark
    validate_disk_space(path, size_bytes)?;

    let mut manager = TempFileManager::new(path, "seq_read")?;
    let temp_path = manager.create_file(size_bytes)?;

    // Fill file with data first
    {
        let mut file = OpenOptions::new().write(true).open(&temp_path)?;
        let buffer = vec![0u8; 1024 * 1024];
        let mut written = 0u64;
        while written < size_bytes {
            let to_write = std::cmp::min(buffer.len() as u64, size_bytes - written);
            file.write_all(&buffer[..to_write as usize])?;
            written += to_write;
        }
        file.sync_all()?;
    }

    // Measure read performance
    let start = Instant::now();
    let mut file = OpenOptions::new().read(true).open(&temp_path)?;
    let mut buffer = vec![0u8; 1024 * 1024];
    let mut total_read = 0u64;

    while total_read < size_bytes {
        let to_read = std::cmp::min(buffer.len() as u64, size_bytes - total_read);
        let bytes_read = file.read(&mut buffer[..to_read as usize])?;
        if bytes_read == 0 {
            break;
        }
        total_read += bytes_read as u64;
    }

    let duration = start.elapsed();
    let throughput_mbps = (total_read as f64 / duration.as_secs_f64()) / 1_048_576.0;

    Ok(SequentialResult {
        throughput_mbps,
        total_bytes: total_read,
        duration,
    })
}

/// Measure sequential write performance
pub fn measure_sequential_write(
    path: &Path,
    size_bytes: u64,
) -> Result<SequentialResult, ProfilingError> {
    super::super::logging::log_info(&format!("Measuring sequential write: {} bytes", size_bytes));

    // Validate disk space before benchmark
    validate_disk_space(path, size_bytes)?;

    let mut manager = TempFileManager::new(path, "seq_write")?;
    let temp_path = manager.create_file(size_bytes)?;

    let start = Instant::now();
    let mut file = OpenOptions::new().write(true).open(&temp_path)?;
    let buffer = vec![0u8; 1024 * 1024];
    let mut total_written = 0u64;

    while total_written < size_bytes {
        let to_write = std::cmp::min(buffer.len() as u64, size_bytes - total_written);
        file.write_all(&buffer[..to_write as usize])?;
        total_written += to_write;
    }

    file.sync_all()?;
    let duration = start.elapsed();
    let throughput_mbps = (total_written as f64 / duration.as_secs_f64()) / 1_048_576.0;

    Ok(SequentialResult {
        throughput_mbps,
        total_bytes: total_written,
        duration,
    })
}
