//! Disk latency measurement

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

use super::super::error::ProfilingError;
use super::super::tempfile::TempFileManager;
use super::super::types::Percentiles;

/// Disk latency result
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DiskLatencyResult {
    pub read_latency_p50_us: f64,
    pub read_latency_p95_us: f64,
    pub read_latency_p99_us: f64,
    pub write_latency_p50_us: f64,
    pub write_latency_p95_us: f64,
    pub write_latency_p99_us: f64,
}

/// Test disk latency with percentile measurements
pub fn test_disk_latency(path: &Path) -> Result<DiskLatencyResult, ProfilingError> {
    super::super::logging::log_info("Testing disk latency");

    let block_size = 4096;
    let size_bytes = 100 * 1024 * 1024; // 100 MB
    let num_samples = 100;

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

    // Fill file
    {
        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 latency
    let mut read_latencies = Vec::with_capacity(num_samples);
    {
        let mut file = OpenOptions::new().read(true).open(&temp_path)?;
        let mut buffer = vec![0u8; block_size];

        for _ in 0..num_samples {
            let offset = rand::random::<u64>() % (size_bytes - block_size as u64);
            let start = Instant::now();
            file.seek(SeekFrom::Start(offset))?;
            file.read(&mut buffer)?;
            read_latencies.push(start.elapsed().as_micros() as f64);
        }
    }

    // Measure write latency
    let mut write_latencies = Vec::with_capacity(num_samples);
    {
        let mut file = OpenOptions::new().write(true).open(&temp_path)?;
        let buffer = vec![0u8; block_size];

        for _ in 0..num_samples {
            let offset = rand::random::<u64>() % (size_bytes - block_size as u64);
            let start = Instant::now();
            file.seek(SeekFrom::Start(offset))?;
            file.write_all(&buffer)?;
            write_latencies.push(start.elapsed().as_micros() as f64);
        }
        file.sync_all()?;
    }

    let read_percentiles = Percentiles::calculate(&mut read_latencies);
    let write_percentiles = Percentiles::calculate(&mut write_latencies);

    Ok(DiskLatencyResult {
        read_latency_p50_us: read_percentiles.p50,
        read_latency_p95_us: read_percentiles.p95,
        read_latency_p99_us: read_percentiles.p99,
        write_latency_p50_us: write_percentiles.p50,
        write_latency_p95_us: write_percentiles.p95,
        write_latency_p99_us: write_percentiles.p99,
    })
}
