//! Core error types for cfgmatic.
//!
//! This module defines the error types used across all cfgmatic crates.

/// Core error type for cfgmatic.
///
/// This error type encompasses all possible errors that can occur
/// during configuration management operations.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// I/O error occurred.
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    /// Parsing error (JSON, TOML, YAML, etc.).
    #[error("Parse error: {0}")]
    Parse(String),

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

    /// Configuration not found.
    #[error("Configuration not found: {0}")]
    NotFound(String),

    /// Merge operation failed.
    #[error("Merge failed: {0}")]
    Merge(String),

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

    /// Custom error with message.
    #[error("{0}")]
    Custom(String),

    /// Multiple errors aggregated.
    #[error("Multiple errors: {0}")]
    Multiple(String),
}

impl Error {
    /// Create a parse error with a message.
    #[must_use]
    pub const fn parse(msg: String) -> Self {
        Self::Parse(msg)
    }

    /// Create a validation error with a message.
    #[must_use]
    pub const fn validation(msg: String) -> Self {
        Self::Validation(msg)
    }

    /// Create a "not found" error.
    #[must_use]
    pub const fn not_found(name: String) -> Self {
        Self::NotFound(name)
    }

    /// Create a merge error with a message.
    #[must_use]
    pub const fn merge(msg: String) -> Self {
        Self::Merge(msg)
    }

    /// Create a custom error with a message.
    #[must_use]
    pub const fn custom(msg: String) -> Self {
        Self::Custom(msg)
    }

    /// Aggregate multiple errors into one.
    #[must_use]
    pub fn multiple(errors: &[Self]) -> Self {
        let msg = errors
            .iter()
            .map(std::string::ToString::to_string)
            .collect::<Vec<_>>()
            .join("; ");
        Self::Multiple(msg)
    }
}

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

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

    #[test]
    fn test_error_creation() {
        let err = Error::parse("failed to parse".to_string());
        assert_eq!(err.to_string(), "Parse error: failed to parse");
    }

    #[test]
    fn test_error_display() {
        let err = Error::not_found("config.toml".to_string());
        assert!(err.to_string().contains("config.toml"));
    }
}
