//! Common types for profiling operations

use std::time::Duration;

use super::error::ProfilingError;

/// Benchmark duration with validation
#[derive(Debug, Clone, Copy)]
pub struct BenchmarkDuration {
    duration: Duration,
}

impl BenchmarkDuration {
    /// Create new benchmark duration with validation
    pub fn new(duration: Duration) -> Result<Self, ProfilingError> {
        const MIN_DURATION: Duration = Duration::from_secs(1);
        const MAX_DURATION: Duration = Duration::from_secs(3600);

        if duration < MIN_DURATION {
            return Err(ProfilingError::InvalidConfig(
                "Duration must be at least 1 second".to_string(),
            ));
        }
        if duration > MAX_DURATION {
            return Err(ProfilingError::InvalidConfig(
                "Duration must not exceed 3600 seconds".to_string(),
            ));
        }

        Ok(Self { duration })
    }

    /// Get the inner duration
    pub fn inner(&self) -> Duration {
        self.duration
    }
}

impl From<BenchmarkDuration> for Duration {
    fn from(bd: BenchmarkDuration) -> Self {
        bd.duration
    }
}

/// ISO 8601 timestamp
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Timestamp {
    iso8601: String,
}

impl Timestamp {
    /// Create new timestamp from current time
    pub fn now() -> Self {
        use chrono::Utc;
        Self {
            iso8601: Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
        }
    }

    /// Get ISO 8601 string
    pub fn as_str(&self) -> &str {
        &self.iso8601
    }
}

impl Default for Timestamp {
    fn default() -> Self {
        Self::now()
    }
}

/// Block size for I/O operations
#[derive(Debug, Clone, Copy)]
pub enum BlockSize {
    Bytes4K = 4096,
    Bytes64K = 65536,
    Bytes1M = 1048576,
}

impl BlockSize {
    /// Get block size in bytes
    pub fn bytes(&self) -> usize {
        *self as usize
    }

    /// Parse from integer
    pub fn from_bytes(bytes: usize) -> Option<Self> {
        match bytes {
            4096 => Some(BlockSize::Bytes4K),
            65536 => Some(BlockSize::Bytes64K),
            1048576 => Some(BlockSize::Bytes1M),
            _ => None,
        }
    }
}

/// Percentile values for latency measurements
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Percentiles {
    pub p50: f64,
    pub p95: f64,
    pub p99: f64,
}

impl Percentiles {
    /// Calculate percentiles from samples
    pub fn calculate(samples: &mut [f64]) -> Self {
        samples.sort_by(|a, b| a.total_cmp(b));
        let len = samples.len();

        let p50_idx = (len as f64 * 0.50) as usize;
        let p95_idx = (len as f64 * 0.95) as usize;
        let p99_idx = (len as f64 * 0.99) as usize;

        Self {
            p50: samples.get(p50_idx).copied().unwrap_or(0.0),
            p95: samples.get(p95_idx).copied().unwrap_or(0.0),
            p99: samples.get(p99_idx).copied().unwrap_or(0.0),
        }
    }
}
