//! Error types for configuration operations.

/// Errors that can occur when working with configuration.
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
    /// Configuration file not found.
    #[error("configuration not found: {0}")]
    NotFound(String),

    /// Failed to parse configuration.
    #[error("failed to parse configuration: {0}")]
    Parse(String),

    /// File operation error.
    #[error("file error: {0}")]
    #[cfg(feature = "files")]
    File(#[from] cfgmatic_files::FileError),

    /// IO error.
    #[error("io error: {0}")]
    Io(#[from] std::io::Error),

    /// Value not found at path.
    #[error("value not found at path: {0}")]
    ValueNotFound(String),

    /// Serialization error.
    #[error("serialization error: {0}")]
    Serialization(String),

    /// Validation error.
    #[error("validation error: {0}")]
    Validation(String),

    /// Environment variable error.
    #[error("environment variable error: {0}")]
    EnvVar(String),

    /// Multiple errors.
    #[error("multiple errors: {0:?}")]
    Multiple(Vec<Self>),
}

/// Result type alias for configuration operations.
pub type Result<T> = std::result::Result<T, ConfigError>;

/// Trait for types that can load fields from environment variables.
///
/// This trait is implemented by the `Config` derive macro.
///
/// # Example
///
/// ```
/// use cfgmatic::{ConfigFields, ConfigError};
///
/// #[derive(Debug, Default)]
/// struct MyConfig {
///     port: u16,
/// }
///
/// impl ConfigFields for MyConfig {
///     fn load_from_env(&mut self, _prefix: Option<&str>) -> Result<(), ConfigError> {
///         // Load fields from environment
///         Ok(())
///     }
///
///     fn env_prefix() -> &'static str {
///         "MYAPP"
///     }
/// }
/// ```
pub trait ConfigFields {
    /// Load fields from environment variables.
    ///
    /// # Arguments
    ///
    /// * `prefix` - Optional prefix to override the struct's default prefix.
    ///
    /// # Errors
    ///
    /// Returns an error if environment variables cannot be parsed.
    fn load_from_env(&mut self, prefix: Option<&str>) -> Result<()>;

    /// Get the default environment variable prefix.
    fn env_prefix() -> &'static str;
}

impl ConfigError {
    /// Create a new parse error.
    ///
    /// # Example
    ///
    /// ```
    /// use cfgmatic::ConfigError;
    ///
    /// let err = ConfigError::parse("invalid value");
    /// ```
    pub fn parse(msg: impl Into<String>) -> Self {
        Self::Parse(msg.into())
    }

    /// Create a new not found error.
    ///
    /// # Example
    ///
    /// ```
    /// use cfgmatic::ConfigError;
    ///
    /// let err = ConfigError::not_found("config.toml");
    /// ```
    pub fn not_found(msg: impl Into<String>) -> Self {
        Self::NotFound(msg.into())
    }

    /// Create a new validation error.
    ///
    /// # Example
    ///
    /// ```
    /// use cfgmatic::ConfigError;
    ///
    /// let err = ConfigError::validation("port must be > 0");
    /// ```
    pub fn validation(msg: impl Into<String>) -> Self {
        Self::Validation(msg.into())
    }
}
