use crate::{parser, InputValueType, Pos, Value};
use serde::Serialize;
use std::collections::BTreeMap;
use std::fmt::{self, Debug, Display, Formatter};
use std::marker::PhantomData;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
#[serde(transparent)]
pub struct ErrorExtensionValues(BTreeMap<String, Value>);
impl ErrorExtensionValues {
    
    pub fn set(&mut self, name: impl AsRef<str>, value: impl Into<Value>) {
        self.0.insert(name.as_ref().to_string(), value.into());
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ServerError {
    
    pub message: String,
    
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub locations: Vec<Pos>,
    
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub path: Vec<PathSegment>,
    
    #[serde(skip_serializing_if = "error_extensions_is_empty")]
    pub extensions: Option<ErrorExtensionValues>,
}
fn error_extensions_is_empty(values: &Option<ErrorExtensionValues>) -> bool {
    match values {
        Some(values) => values.0.is_empty(),
        None => true,
    }
}
impl ServerError {
    
    pub fn new(message: impl Into<String>) -> Self {
        Self {
            message: message.into(),
            locations: Vec::new(),
            path: Vec::new(),
            extensions: None,
        }
    }
    
    pub fn at(mut self, at: Pos) -> Self {
        self.locations.push(at);
        self
    }
    
    pub fn path(mut self, path: PathSegment) -> Self {
        self.path.insert(0, path);
        self
    }
}
impl Display for ServerError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(&self.message)
    }
}
impl From<ServerError> for Vec<ServerError> {
    fn from(single: ServerError) -> Self {
        vec![single]
    }
}
impl From<Error> for ServerError {
    fn from(e: Error) -> Self {
        e.into_server_error()
    }
}
impl From<parser::Error> for ServerError {
    fn from(e: parser::Error) -> Self {
        Self {
            message: e.to_string(),
            locations: e.positions().collect(),
            path: Vec::new(),
            extensions: None,
        }
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(untagged)]
pub enum PathSegment {
    
    Field(String),
    
    Index(usize),
}
pub type ServerResult<T> = std::result::Result<T, ServerError>;
#[derive(Debug)]
pub struct InputValueError<T> {
    message: String,
    phantom: PhantomData<T>,
}
impl<T: InputValueType> InputValueError<T> {
    fn new(message: String) -> Self {
        Self {
            message,
            phantom: PhantomData,
        }
    }
    
    #[must_use]
    pub fn expected_type(actual: Value) -> Self {
        Self::new(format!(
            r#"Expected input type "{}", found {}."#,
            T::type_name(),
            actual
        ))
    }
    
    
    
    
    #[must_use]
    pub fn custom(msg: impl Display) -> Self {
        Self::new(format!(r#"Failed to parse "{}": {}"#, T::type_name(), msg))
    }
    
    pub fn propagate<U: InputValueType>(self) -> InputValueError<U> {
        InputValueError::new(format!(
            r#"{} (occurred while parsing "{}")"#,
            self.message,
            U::type_name()
        ))
    }
    
    pub fn into_server_error(self) -> ServerError {
        ServerError::new(self.message)
    }
}
impl<T: InputValueType, E: Display> From<E> for InputValueError<T> {
    fn from(error: E) -> Self {
        Self::custom(error)
    }
}
pub type InputValueResult<T> = Result<T, InputValueError<T>>;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Error {
    
    pub message: String,
    
    #[serde(skip_serializing_if = "error_extensions_is_empty")]
    pub extensions: Option<ErrorExtensionValues>,
}
impl Error {
    
    pub fn new(message: impl Into<String>) -> Self {
        Self {
            message: message.into(),
            extensions: None,
        }
    }
    
    #[must_use]
    pub fn into_server_error(self) -> ServerError {
        ServerError {
            message: self.message,
            locations: Vec::new(),
            path: Vec::new(),
            extensions: self.extensions,
        }
    }
}
impl<T: Display> From<T> for Error {
    fn from(e: T) -> Self {
        Self {
            message: e.to_string(),
            extensions: None,
        }
    }
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ParseRequestError {
    
    #[error("{0}")]
    Io(#[from] std::io::Error),
    
    #[error("Invalid request: {0}")]
    InvalidRequest(serde_json::Error),
    
    #[error("Invalid files map: {0}")]
    InvalidFilesMap(serde_json::Error),
    
    #[error("Invalid multipart data")]
    #[cfg(feature = "multipart")]
    #[cfg_attr(feature = "nightly", doc(cfg(feature = "multipart")))]
    InvalidMultipart(multer::Error),
    
    #[error("Missing \"operators\" part")]
    MissingOperatorsPart,
    
    #[error("Missing \"map\" part")]
    MissingMapPart,
    
    #[error("It's not an upload operation")]
    NotUpload,
    
    #[error("Missing files")]
    MissingFiles,
    
    #[error("Payload too large")]
    PayloadTooLarge,
    
    #[error("Batch requests are not supported")]
    UnsupportedBatch,
}
#[cfg(feature = "multipart")]
impl From<multer::Error> for ParseRequestError {
    fn from(err: multer::Error) -> Self {
        match err {
            multer::Error::FieldSizeExceeded { .. } | multer::Error::StreamSizeExceeded { .. } => {
                ParseRequestError::PayloadTooLarge
            }
            _ => ParseRequestError::InvalidMultipart(err),
        }
    }
}
pub trait ErrorExtensions: Sized {
    
    fn extend(&self) -> Error;
    
    fn extend_with<C>(self, cb: C) -> Error
    where
        C: FnOnce(&Self, &mut ErrorExtensionValues),
    {
        let message = self.extend().message;
        let mut extensions = self.extend().extensions.unwrap_or_default();
        cb(&self, &mut extensions);
        Error {
            message,
            extensions: Some(extensions),
        }
    }
}
impl ErrorExtensions for Error {
    fn extend(&self) -> Error {
        self.clone()
    }
}
impl<E: std::fmt::Display> ErrorExtensions for &E {
    fn extend(&self) -> Error {
        Error {
            message: format!("{}", self),
            extensions: None,
        }
    }
}
pub trait ResultExt<T, E>: Sized {
    
    fn extend_err<C>(self, cb: C) -> Result<T>
    where
        C: FnOnce(&E, &mut ErrorExtensionValues);
    
    fn extend(self) -> Result<T>;
}
impl<T, E> ResultExt<T, E> for std::result::Result<T, E>
where
    E: ErrorExtensions + Send + Sync + 'static,
{
    fn extend_err<C>(self, cb: C) -> Result<T>
    where
        C: FnOnce(&E, &mut ErrorExtensionValues),
    {
        match self {
            Err(err) => Err(err.extend_with(|e, ee| cb(e, ee))),
            Ok(value) => Ok(value),
        }
    }
    fn extend(self) -> Result<T> {
        match self {
            Err(err) => Err(err.extend()),
            Ok(value) => Ok(value),
        }
    }
}