use base64::DecodeError;
use crypto_box::aead::Error as AeadError;
use ed25519_dalek::SignatureError;
use reqwest::Error as ReqwestError;
use serde::Deserialize;
use sqlx::migrate::MigrateError;
use std::error::Error;
///
/// The primary error type for Ringspace. Used to unify errors from
/// multiple other sources for sensible outputs.
///
#[derive(Debug, Deserialize)]
pub struct RingspaceError {
    pub msg: String,
}

impl RingspaceError {
    pub fn new(msg: String) -> Self {
        RingspaceError { msg }
    }
}

impl std::fmt::Display for RingspaceError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.msg)
    }
}

impl Error for RingspaceError {}

impl From<&str> for RingspaceError {
    fn from(e: &str) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

impl From<sqlx::Error> for RingspaceError {
    fn from(e: sqlx::Error) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

impl From<std::string::FromUtf8Error> for RingspaceError {
    fn from(e: std::string::FromUtf8Error) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

impl From<uuid::Error> for RingspaceError {
    fn from(e: uuid::Error) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

impl From<ReqwestError> for RingspaceError {
    fn from(e: ReqwestError) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

impl From<SignatureError> for RingspaceError {
    fn from(e: SignatureError) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

impl From<serde_json::Error> for RingspaceError {
    fn from(e: serde_json::Error) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

impl From<MigrateError> for RingspaceError {
    fn from(e: MigrateError) -> Self {
        RingspaceError { msg: e.to_string() }
    }
}

// For signatures
impl From<Vec<u8>> for RingspaceError {
    fn from(v: Vec<u8>) -> Self {
        RingspaceError {
            msg: format!("Byte conversion failed: {:?}", v),
        }
    }
}

impl From<DecodeError> for RingspaceError {
    fn from(e: DecodeError) -> Self {
        match e {
            DecodeError::InvalidByte(offset, bad) => RingspaceError {
                msg: format!("Base64 decode: Bad byte {bad} at postition {offset}"),
            },
            DecodeError::InvalidLength(length) => RingspaceError {
                msg: format!("Base64 decode: Invalid length {length}"),
            },
            DecodeError::InvalidLastSymbol(offset, bad) => RingspaceError {
                msg: format!("Base64 decode: Invalid last symbol {bad} at offset {offset}"),
            },
            DecodeError::InvalidPadding => RingspaceError {
                msg: String::from("Base64 decode: Invalid padding"),
            },
        }
    }
}

impl From<AeadError> for RingspaceError {
    fn from(e: AeadError) -> Self {
        RingspaceError {
            msg: format!("{e}"),
        }
    }
}

impl From<dotenvy::Error> for RingspaceError {
    fn from(e: dotenvy::Error) -> Self {
        RingspaceError {
            msg: format!("{e}"),
        }
    }
}
