use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};

#[derive(Debug)]
pub enum DatabaseError {
	DeleteError,
	InsertError(diesel::result::Error),
	InsertGetError,
	NotFound,
	Protected,
	UpdateError(diesel::result::Error),
}

impl DatabaseError {
	fn get_code(&self) -> StatusCode {
		match self {
			DatabaseError::NotFound => StatusCode::NOT_FOUND,
			DatabaseError::Protected => StatusCode::FORBIDDEN,
			_ => StatusCode::INTERNAL_SERVER_ERROR,
		}
	}
}

impl Serialize for DatabaseError {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		let mut s = serializer.serialize_struct("error", 3)?;
		s.serialize_field("type", "database-error")?;
		s.serialize_field("code", &self.get_code().as_u16())?;
		s.serialize_field("description", &String::from(self))?;
		s.end()
	}
}

impl From<&DatabaseError> for String {
	fn from(err: &DatabaseError) -> Self {
		match err {
			DatabaseError::InsertError(_) => String::from("error on inserting into database"),
			DatabaseError::InsertGetError => {
				String::from("error on retrieving new entry from database (your entry was saved)")
			}
			DatabaseError::NotFound => String::from("model was not found in database"),
			DatabaseError::DeleteError => String::from("error on deleting from database"),
			DatabaseError::Protected => String::from("model is protected"),
			DatabaseError::UpdateError(_) => String::from("error on updating the model"),
		}
	}
}

impl From<DatabaseError> for HttpResponse {
	fn from(err: DatabaseError) -> Self {
		HttpResponse::build(err.get_code()).json(err)
	}
}