//! Error types for profiling operations

use rhai::EvalAltResult;

/// Error type for all profiling operations
#[derive(Debug, Clone, thiserror::Error)]
pub enum ProfilingError {
    /// iperf3 binary not found in PATH
    #[error("iperf3 binary not found in PATH")]
    Iperf3NotFound,
    /// iperf3 execution failed
    #[error("iperf3 execution failed: {0}")]
    Iperf3Failed(String),
    /// File system or I/O error
    #[error("I/O error: {0}")]
    IoError(String),
    /// Insufficient permissions
    #[error("Permission denied: {0}")]
    PermissionDenied(String),
    /// Invalid configuration parameter
    #[error("Invalid configuration: {0}")]
    InvalidConfig(String),
    /// Failed to parse output
    #[error("Parse error: {0}")]
    ParseError(String),
    /// Operation timed out
    #[error("Operation timed out")]
    Timeout,
    /// Operation was cancelled
    #[error("Operation was cancelled")]
    Cancelled,
    /// Memory allocation failed
    #[error("Memory error: {0}")]
    MemoryError(String),
    /// CPU benchmarking error
    #[error("CPU error: {0}")]
    CpuError(String),
    /// Network connectivity error
    #[error("Network error: {0}")]
    NetworkError(String),
    /// Disk space insufficient
    #[error("Insufficient disk space: required {required}MB, available {available}MB")]
    InsufficientSpace { required: u64, available: u64 },
    /// Resource exhaustion
    #[error("Resource exhausted: {0}")]
    ResourceExhausted(String),
}

impl From<std::io::Error> for ProfilingError {
    fn from(err: std::io::Error) -> Self {
        ProfilingError::IoError(err.to_string())
    }
}

/// A trait for converting a Result to a Rhai-compatible error
pub trait ToRhaiError<T> {
    fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>>;
}

impl<T> ToRhaiError<T> for Result<T, ProfilingError> {
    fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
        self.map_err(|e| {
            Box::new(EvalAltResult::ErrorRuntime(
                e.to_string().into(),
                rhai::Position::NONE,
            ))
        })
    }
}

// Implementation for std::io::Error specifically
impl<T> ToRhaiError<T> for Result<T, std::io::Error> {
    fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
        self.map_err(|e| {
            let profiling_error = ProfilingError::IoError(e.to_string());
            Box::new(EvalAltResult::ErrorRuntime(
                profiling_error.to_string().into(),
                rhai::Position::NONE,
            ))
        })
    }
}
