use thiserror::Error;

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum SchemaError {
    #[error("missing required field at {path}")]
    MissingField { path: String },
    #[error("invalid value at {path}: expected {expected}, got {actual}")]
    InvalidType {
        path: String,
        expected: &'static str,
        actual: &'static str,
    },
    #[error("invalid enum value at {path}: expected one of {expected:?}, got {actual}")]
    InvalidEnumValue {
        path: String,
        expected: Vec<String>,
        actual: String,
    },
    #[error("no matching oneof variant at {path}")]
    OneofMismatch { path: String },
}

impl SchemaError {
    pub fn missing_field(path: impl Into<String>) -> Self {
        Self::MissingField { path: path.into() }
    }

    pub fn invalid_type(
        path: impl Into<String>,
        expected: &'static str,
        actual: &'static str,
    ) -> Self {
        Self::InvalidType {
            path: path.into(),
            expected,
            actual,
        }
    }

    pub fn invalid_enum_value(
        path: impl Into<String>,
        expected: Vec<String>,
        actual: impl Into<String>,
    ) -> Self {
        Self::InvalidEnumValue {
            path: path.into(),
            expected,
            actual: actual.into(),
        }
    }

    pub fn oneof_mismatch(path: impl Into<String>) -> Self {
        Self::OneofMismatch { path: path.into() }
    }
}
