use std::fmt;
use std::time::SystemTime;

use sequoia_openpgp as openpgp;
use openpgp::packet::UserID;
use openpgp::cert::prelude::*;

use crate::RevocationStatus;

/// Encapsulates an OpenPGP User ID.
///
/// This holds the information about a User ID that is relevant to web
/// of trust calculations.
#[derive(Debug, Clone)]
pub struct UserIDSynopsis {
    userid: UserID,
    binding_signature_creation_time: SystemTime,
    revocation_status: RevocationStatus,
}

impl<'a> From<&ValidUserIDAmalgamation<'a>> for UserIDSynopsis {
    fn from(ua: &ValidUserIDAmalgamation<'a>) -> Self {
        UserIDSynopsis {
            userid: ua.userid().clone(),
            binding_signature_creation_time:
                ua.binding_signature()
                .signature_creation_time()
                .expect("valid"),
            revocation_status: ua.revocation_status().into(),
        }
    }
}

impl<'a> From<ValidUserIDAmalgamation<'a>> for UserIDSynopsis {
    fn from(ua: ValidUserIDAmalgamation<'a>) -> Self {
        (&ua).into()
    }
}

impl<'a> From<(&[u8], SystemTime)> for UserIDSynopsis {
    fn from(userid: (&[u8], SystemTime)) -> Self {
        (UserID::from(userid.0), userid.1).into()
    }
}

impl<'a> From<&[u8]> for UserIDSynopsis {
    fn from(userid: &[u8]) -> Self {
        (userid, SystemTime::now()).into()
    }
}

impl<'a> From<(&str, SystemTime)> for UserIDSynopsis {
    fn from(userid: (&str, SystemTime)) -> Self {
        (userid.0.as_bytes(), userid.1).into()
    }
}

impl<'a> From<&str> for UserIDSynopsis {
    fn from(userid: &str) -> Self {
        (userid, SystemTime::now()).into()
    }
}

impl<'a> From<(UserID, SystemTime)> for UserIDSynopsis {
    fn from(userid: (UserID, SystemTime)) -> Self {
        UserIDSynopsis {
            userid: userid.0,
            binding_signature_creation_time: userid.1,
            revocation_status: RevocationStatus::NotAsFarAsWeKnow,
        }
    }
}

impl<'a> From<UserID> for UserIDSynopsis {
    fn from(userid: UserID) -> Self {
        (userid, SystemTime::now()).into()
    }
}

impl fmt::Display for UserIDSynopsis {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(
            format_args!(
                "{} ({})",
                String::from_utf8_lossy(self.userid.value()),
                match self.revocation_status {
                    RevocationStatus::NotAsFarAsWeKnow => "",
                    RevocationStatus::Hard =>
                        "hard revoked",
                    RevocationStatus::Soft(_t) =>
                        "soft revoked",
                }))
    }
}

impl UserIDSynopsis {
    /// Returns the User ID.
    pub fn userid(&self) -> &UserID {
        &self.userid
    }

    /// Returns the User ID's value.
    pub fn value(&self) -> &[u8] {
        &self.userid.value()
    }

    /// Returns the certificate's revocation status.
    pub fn revocation_status(&self) -> RevocationStatus {
        self.revocation_status.clone()
    }

    /// Returns the binding signature's creation time.
    pub fn binding_signature_creation_time(&self) -> SystemTime {
        self.binding_signature_creation_time
    }
}
