use {
    crate::signup::GithubEmail,
    chrono::{DateTime, Utc},
    serde::{Deserialize, Serialize},
    serde_repr::{Deserialize_repr, Serialize_repr},
    std::fmt::{Display, Formatter},
    tsync::tsync,
};

// smbcloud Users.
#[derive(Debug, Serialize, Deserialize)]
#[tsync]
pub struct User {
    pub id: i32,
    pub email: String,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

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

#[derive(Debug, Serialize, Deserialize)]
pub struct Status {
    pub code: Option<i32>,
    pub message: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[tsync]
pub struct Data {
    pub id: i32,
    pub email: String,
    pub created_at: String,
}

/// This is smbCloud authorization model
/// that is currently tightly coupled with GitHub OAuth model.
#[derive(Debug, Serialize, Deserialize)]
pub struct SmbAuthorization {
    pub message: String,
    pub user: Option<User>,
    pub user_email: Option<GithubEmail>,
    pub user_info: Option<GithubInfo>,
    pub error_code: Option<ErrorCode>,
}

/// TODO: Move to ErrorResponse
#[derive(Debug, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u32)]
#[tsync]
pub enum ErrorCode {
    EmailNotFound = 1000,
    EmailUnverified = 1001,
    EmailConfirmationFailed = 1002,
    PasswordNotSet = 1003,
    GithubNotLinked = 1004,
    EmailAlreadyExist = 1005,
    InvalidPassword = 1006,
    HostedMailAccountUnverified = 1007,
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            ErrorCode::EmailNotFound => write!(f, "Email not found."),
            ErrorCode::EmailUnverified => write!(f, "Email not verified."),
            ErrorCode::EmailConfirmationFailed => write!(f, "Email confirmation failed."),
            ErrorCode::PasswordNotSet => write!(f, "Password not set."),
            ErrorCode::GithubNotLinked => write!(f, "Github not connected."),
            ErrorCode::EmailAlreadyExist => write!(f, "Email already exists."),
            ErrorCode::InvalidPassword => write!(f, "Invalid password."),
            ErrorCode::HostedMailAccountUnverified => {
                write!(f, "Hosted mail account not fully activated yet.")
            }
        }
    }
}

impl Copy for ErrorCode {}

impl Clone for ErrorCode {
    fn clone(&self) -> Self {
        *self
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GithubInfo {
    pub id: i64,
    pub login: String,
    pub name: String,
    pub avatar_url: String,
    pub html_url: String,
    pub email: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;
    #[test]
    fn test_smb_authorization() {
        let smb_authorization = SmbAuthorization {
            message: "test".to_owned(),
            user: None,
            user_email: None,
            user_info: None,
            error_code: Some(ErrorCode::EmailUnverified),
        };
        let json = json!({
            "message": "test",
            "user": null,
            "user_email": null,
            "user_info": null,
            "error_code": 1001,
        });
        assert_eq!(serde_json::to_value(smb_authorization).unwrap(), json);
    }
}
