//! Error types for fluid properties calculations.
//!
//! This module defines the `FluidError` enum that represents all possible errors
//! that can occur when querying fluid properties.

use thiserror::Error;

/// Errors that can occur when working with fluid properties.
#[derive(Error, Debug, Clone)]
pub enum FluidError {
    /// The requested fluid is not available in the backend.
    #[error("Fluid `{fluid}` not found")]
    UnknownFluid {
        /// The fluid identifier that was requested
        fluid: String,
    },

    /// The thermodynamic state is invalid for the requested property.
    #[error("Invalid state for property calculation: {reason}")]
    InvalidState {
        /// The reason why the state is invalid
        reason: String,
    },

    /// Error from CoolProp C++ library.
    #[error("CoolProp error: {0}")]
    CoolPropError(String),

    /// Critical point data is not available for the given fluid.
    #[error("Critical point not available for `{fluid}`")]
    NoCriticalPoint {
        /// The fluid identifier that was requested
        fluid: String,
    },

    /// The requested property is not supported by this backend.
    #[error("Property `{property}` not supported")]
    UnsupportedProperty {
        /// The property that is not supported
        property: String,
    },

    /// Numerical error during calculation (overflow, NaN, etc).
    #[error("Numerical error: {0}")]
    NumericalError(String),

    /// State is outside the tabular data bounds.
    #[error("State ({p:.2} Pa, {t:.2} K) outside table bounds for fluid `{fluid}`")]
    OutOfBounds {
        /// Fluid identifier
        fluid: String,
        /// Pressure in Pa
        p: f64,
        /// Temperature in K
        t: f64,
    },

    /// Table file could not be found or loaded.
    #[error("Table file not found: {path}")]
    TableNotFound {
        /// Path that was attempted
        path: String,
    },

    /// Mixture is not supported by the backend.
    #[error("Mixture not supported: {0}")]
    MixtureNotSupported(String),
}

/// Result type alias for fluid operations.
pub type FluidResult<T> = Result<T, FluidError>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_unknown_fluid_error() {
        let err = FluidError::UnknownFluid {
            fluid: "R999".to_string(),
        };
        assert_eq!(format!("{}", err), "Fluid `R999` not found");
    }

    #[test]
    fn test_invalid_state_error() {
        let err = FluidError::InvalidState {
            reason: "Pressure below triple point".to_string(),
        };
        assert_eq!(
            format!("{}", err),
            "Invalid state for property calculation: Pressure below triple point"
        );
    }

    #[test]
    fn test_error_clone() {
        let err1 = FluidError::UnknownFluid {
            fluid: "R134a".to_string(),
        };
        let err2 = err1.clone();
        assert_eq!(format!("{}", err1), format!("{}", err2));
    }
}
