
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey};
use serde::{Deserialize, Serialize};

use crate::{make_decoding_key, make_encoding_key};

/// Passport options for config files with keys parsed for `jsonwebtoken`
#[derive(Clone, Debug)]
pub struct JwtParsedKeyConfig {
    /// Signing algorithm to use 
    pub algorithm: Algorithm,
    /// Optional offset for token expiry in seconds
    pub expires_in: Option<u32>,
    /// Key used for verification of passports
    pub public_key: DecodingKey<'static>,
    /// Key used for signing of passports
    pub private_key: EncodingKey,
    /// Unparsed key used for verification of passports
    pub unparsed_public_key: String,
    /// Unparsed key used for singing of passports
    pub unparsed_private_key: String,
}

impl<'de> Deserialize<'de> for JwtParsedKeyConfig {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de> {
        JwtKeyConfig::deserialize(deserializer)?
            .parse_keys()
            .map_err(|e| serde::de::Error::custom(e.to_string()))
    }
}

/// Passport options for config files
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JwtKeyConfig {
    /// Signing algorithm to use
    pub algorithm: Algorithm,
    /// Optional offset for token expiry in seconds
    pub expires_in: Option<u32>,
    /// Key used for signature verification of passports
    pub public_key: String,
    /// Key used for signing of passports (and verification in symmetric cryptography)
    pub private_key: String,
}

impl JwtKeyConfig {
    /// Parses the keys for `jsonwebtoken` and returns a new `JwtParsedKeyConfig`
    pub fn parse_keys(&self) -> jsonwebtoken::errors::Result<JwtParsedKeyConfig> {
        Ok(JwtParsedKeyConfig {
            algorithm: self.algorithm,
            expires_in: self.expires_in,
            public_key: self.decoding_key()?,
            private_key: self.encoding_key()?,
            unparsed_public_key: self.public_key.clone(),
            unparsed_private_key: self.private_key.clone(),
        })
    }

    /// Parses the encoding key for `jsonwebtoken`
    pub fn encoding_key(&self) -> jsonwebtoken::errors::Result<EncodingKey> {
        make_encoding_key(self.private_key.as_bytes(), self.algorithm)
    }

    /// Parses the decoding key for `jsonwebtoken`
    pub fn decoding_key(&self) -> jsonwebtoken::errors::Result<DecodingKey<'static>> {
        make_decoding_key(self.public_key.as_bytes(), self.algorithm).map(DecodingKey::into_static)
    }
}
