use dup_crypto::{keys::SigError, private_message::PrivateMessageError};
use serde::{Deserialize, Serialize};
use std::convert::From;

#[derive(Debug)]
pub enum Error {
	CouldNotCreateDir,
	DatabaseError(sled::Error),
	DeserializationError,
	DocumentError(DocumentError),
	//IdentityNotMember,
	InvalidConfirms,
	NetworkError(NetworkError),
	ResponseError(ResponseError),
	//TxNotFound,
	//UnknownHttpError(u16),
}

impl From<DocumentError> for Error {
	fn from(e: DocumentError) -> Self {
		Self::DocumentError(e)
	}
}

impl From<NetworkError> for Error {
	fn from(e: NetworkError) -> Self {
		Self::NetworkError(e)
	}
}

impl From<ResponseError> for Error {
	fn from(e: ResponseError) -> Self {
		Self::ResponseError(e)
	}
}

impl From<serde_json::Error> for Error {
	fn from(_: serde_json::Error) -> Self {
		Self::DeserializationError
	}
}

impl From<bincode::Error> for Error {
	fn from(_: bincode::Error) -> Self {
		Self::DocumentError(DocumentError::DeserializationFailed)
	}
}

impl From<reqwest::Error> for Error {
	fn from(_: reqwest::Error) -> Self {
		Self::NetworkError(NetworkError::ConnectionError)
	}
}

impl From<sled::Error> for Error {
	fn from(e: sled::Error) -> Self {
		Self::DatabaseError(e)
	}
}

#[derive(Debug)]
pub enum DocumentError {
	DecryptionFailed,
	DeserializationFailed,
	DifferentCurrency,
	IncoherentPositionMarkers,
	MissingSignature,
	PrivateMessageError(PrivateMessageError),
	ValidationFailed(ValidationError),
	UnexpectedSignature,
}

#[derive(Debug, Deserialize, Serialize)]
pub enum ValidationError {
	Expired,
	ExpireTimeOverflow,
	InvalidPublicKey,
	InvalidSignature,
	SignedInFuture,
}

impl From<bincode::Error> for DocumentError {
	fn from(_: bincode::Error) -> Self {
		Self::DeserializationFailed
	}
}

impl From<SigError> for DocumentError {
	fn from(_: SigError) -> Self {
		Self::ValidationFailed(ValidationError::InvalidSignature)
	}
}

impl From<PrivateMessageError> for DocumentError {
	fn from(e: PrivateMessageError) -> Self {
		Self::PrivateMessageError(e)
	}
}

#[derive(Debug)]
pub enum NetworkError {
	ConnectionError,
	DeserializationFailed(String),
}

impl From<reqwest::Error> for NetworkError {
	fn from(_: reqwest::Error) -> Self {
		Self::ConnectionError
	}
}

#[derive(Debug, Deserialize, Serialize)]
pub enum ResponseError {
	AlreadyHaveDocument,
	AmountTooSmall,
	ConfirmNotFound,
	DecryptionFailed,
	DemandNotFound,
	DeserializationFailed,
	DifferentCurrency,
	EmptyMixConfirmOnion,
	IncoherentPositionMarkers,
	InternalError,
	MissingSignature,
	OtherError,
	PrivateMessageError,
	ValidationFailed(ValidationError),
	UnexpectedSignature,
	UnknownTxIdListHash,
}

impl From<DocumentError> for ResponseError {
	fn from(e: DocumentError) -> Self {
		match e {
			DocumentError::DecryptionFailed => Self::DecryptionFailed,
			DocumentError::DeserializationFailed => Self::DeserializationFailed,
			DocumentError::DifferentCurrency => Self::DifferentCurrency,
			DocumentError::IncoherentPositionMarkers => Self::IncoherentPositionMarkers,
			DocumentError::MissingSignature => Self::MissingSignature,
			DocumentError::PrivateMessageError(_) => Self::PrivateMessageError,
			DocumentError::ValidationFailed(v) => Self::ValidationFailed(v),
			DocumentError::UnexpectedSignature => Self::UnexpectedSignature,
		}
	}
}

impl From<Error> for ResponseError {
	fn from(e: Error) -> Self {
		match e {
			Error::CouldNotCreateDir => Self::InternalError,
			Error::DatabaseError(_) => Self::InternalError,
			Error::DeserializationError => Self::DeserializationFailed,
			Error::DocumentError(v) => Self::from(v),
			_ => Self::OtherError,
		}
	}
}

impl From<sled::Error> for ResponseError {
	fn from(_: sled::Error) -> Self {
		Self::InternalError
	}
}

#[derive(Debug)]
pub enum ClientError {
	//NetworkError(NetworkError),
	NoNodeError,
	NoWorkingNodeError,
	//ResponseError(ResponseError),
}

#[derive(Debug)]
pub enum PubkeyDecodeError {
	FormatError,
	DecodeError(dup_crypto::bases::BaseConversionError),
	ChecksumError,
}

impl ToString for PubkeyDecodeError {
	fn to_string(&self) -> String {
		String::from(match self {
			Self::FormatError => "Invalid pubkey format",
			Self::DecodeError(e) => {
				return e.to_string();
			}
			Self::ChecksumError => "Invalid pubkey checksum",
		})
	}
}