//! Error handling for {{TOOL_NAME}}
//!
//! Uses canonical error struct pattern following Microsoft Pragmatic Rust Guidelines.

use std::error::Error;
use std::fmt;
use std::backtrace::Backtrace;

/// {{TOOL_NAME}} error result type
pub type Result<T> = std::result::Result<T, {{ToolName}}Error>;

/// {{TOOL_NAME}} error kinds
#[derive(Debug)]
#[non_exhaustive]
pub enum {{ToolName}}ErrorKind {
    /// Configuration error
    ConfigError(String),
    /// I/O error
    IoError(String),
    /// Validation error
    ValidationError(String),
    /// Database error
    DatabaseError(String),
    /// Unknown error
    Unknown(String),
}

impl fmt::Display for {{ToolName}}ErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::ConfigError(msg) => write!(f, "Configuration error: {}", msg),
            Self::IoError(msg) => write!(f, "I/O error: {}", msg),
            Self::ValidationError(msg) => write!(f, "Validation error: {}", msg),
            Self::DatabaseError(msg) => write!(f, "Database error: {}", msg),
            Self::Unknown(msg) => write!(f, "Unknown error: {}", msg),
        }
    }
}

/// {{TOOL_NAME}} error with context
pub struct {{ToolName}}Error {
    /// Error kind
    pub kind: {{ToolName}}ErrorKind,
    /// Context about what was happening
    pub context: String,
    /// Root cause if available
    pub source: Option<Box<dyn Error + Send + Sync>>,
    /// Backtrace for debugging
    pub backtrace: Backtrace,
}

impl {{ToolName}}Error {
    /// Create a new error with kind and context
    pub fn new(kind: {{ToolName}}ErrorKind, context: impl Into<String>) -> Self {
        Self {
            kind,
            context: context.into(),
            source: None,
            backtrace: Backtrace::capture(),
        }
    }

    /// Add source error
    pub fn with_source(mut self, source: Box<dyn Error + Send + Sync>) -> Self {
        self.source = Some(source);
        self
    }
}

impl fmt::Debug for {{ToolName}}Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("{{ToolName}}Error")
            .field("kind", &self.kind)
            .field("context", &self.context)
            .field("source", &self.source)
            .finish()
    }
}

impl fmt::Display for {{ToolName}}Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", self.kind, self.context)
    }
}

impl Error for {{ToolName}}Error {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.source.as_ref().map(|e| e.as_ref() as &(dyn Error + 'static))
    }
}

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

    #[test]
    fn test_error_creation() {
        let err = {{ToolName}}Error::new(
            {{ToolName}}ErrorKind::ConfigError("test".into()),
            "test context",
        );
        assert_eq!(err.context, "test context");
        assert!(err.source.is_none());
    }

    #[test]
    fn test_error_display() {
        let err = {{ToolName}}Error::new(
            {{ToolName}}ErrorKind::ValidationError("invalid input".into()),
            "during validation",
        );
        let msg = format!("{}", err);
        assert!(msg.contains("invalid input"));
        assert!(msg.contains("during validation"));
    }
}
