//! PKCE (Proof Key for Code Exchange) implementation
//!
//! Generates cryptographically secure code verifiers and SHA-256 challenges
//! for OAuth 2.0 PKCE flows.

use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use rand::Rng;
use sha2::{Digest, Sha256};

/// PKCE code verifier and challenge pair
#[derive(Debug, Clone)]
pub struct Pkce {
    /// The code verifier (random string, kept secret until token exchange)
    pub verifier: String,
    /// The code challenge (SHA-256 hash of verifier, sent during authorization)
    pub challenge: String,
}

impl Pkce {
    /// Generate a new PKCE verifier/challenge pair
    ///
    /// - Verifier: 32 random bytes, base64url encoded (43 chars)
    /// - Challenge: SHA-256 of verifier, base64url encoded
    pub fn generate() -> Self {
        let verifier = generate_verifier();
        let challenge = generate_challenge(&verifier);
        Self { verifier, challenge }
    }

    /// The challenge method (always S256 for this implementation)
    pub fn method() -> &'static str {
        "S256"
    }
}

/// Generate a cryptographically random code verifier
fn generate_verifier() -> String {
    let mut rng = rand::thread_rng();
    let bytes: [u8; 32] = rng.gen();
    URL_SAFE_NO_PAD.encode(bytes)
}

/// Generate SHA-256 challenge from verifier
fn generate_challenge(verifier: &str) -> String {
    let mut hasher = Sha256::new();
    hasher.update(verifier.as_bytes());
    let hash = hasher.finalize();
    URL_SAFE_NO_PAD.encode(hash)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_pkce_generation() {
        let pkce = Pkce::generate();

        // Verifier should be 43 chars (32 bytes base64url encoded)
        assert_eq!(pkce.verifier.len(), 43);

        // Challenge should be 43 chars (32 bytes SHA-256 base64url encoded)
        assert_eq!(pkce.challenge.len(), 43);

        // Verify challenge is correct hash of verifier
        let expected_challenge = generate_challenge(&pkce.verifier);
        assert_eq!(pkce.challenge, expected_challenge);
    }

    #[test]
    fn test_pkce_uniqueness() {
        let pkce1 = Pkce::generate();
        let pkce2 = Pkce::generate();

        // Each generation should be unique
        assert_ne!(pkce1.verifier, pkce2.verifier);
        assert_ne!(pkce1.challenge, pkce2.challenge);
    }

    #[test]
    fn test_method() {
        assert_eq!(Pkce::method(), "S256");
    }
}
