use std::error::Error;
use std::fmt::{Display, Formatter};

pub type TrazaeoResult<T> = Result<T, TrazaeoError>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TrazaeoError {
    InvalidInput {
        context: &'static str,
        details: String,
    },
    Validation {
        context: &'static str,
        details: Vec<String>,
    },
    Io {
        context: &'static str,
        details: String,
    },
    Serialization {
        context: &'static str,
        details: String,
    },
    External {
        context: &'static str,
        details: String,
    },
}

impl TrazaeoError {
    pub fn invalid_input(context: &'static str, details: impl Into<String>) -> Self {
        Self::InvalidInput {
            context,
            details: details.into(),
        }
    }

    pub fn validation(context: &'static str, details: Vec<String>) -> Self {
        Self::Validation { context, details }
    }

    pub fn io(context: &'static str, details: impl Into<String>) -> Self {
        Self::Io {
            context,
            details: details.into(),
        }
    }

    pub fn serialization(context: &'static str, details: impl Into<String>) -> Self {
        Self::Serialization {
            context,
            details: details.into(),
        }
    }

    pub fn external(context: &'static str, details: impl Into<String>) -> Self {
        Self::External {
            context,
            details: details.into(),
        }
    }
}

impl Display for TrazaeoError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InvalidInput { context, details } => write!(f, "{context}: {details}"),
            Self::Validation { context, details } => write!(f, "{context}: {}", details.join("; ")),
            Self::Io { context, details } => write!(f, "{context}: {details}"),
            Self::Serialization { context, details } => write!(f, "{context}: {details}"),
            Self::External { context, details } => write!(f, "{context}: {details}"),
        }
    }
}

impl Error for TrazaeoError {}
