use argon2::{
    Argon2,
    password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng},
};

use crate::error::{AuthError, AuthResult};

/// Hash a plaintext password using Argon2 with a random salt.
///
/// Returns a PHC-format string suitable for database storage.
pub fn hash_password(plain: &str) -> AuthResult<String> {
    let salt = SaltString::generate(&mut OsRng);
    let argon2 = Argon2::default();
    let hash = argon2
        .hash_password(plain.as_bytes(), &salt)
        .map_err(|e| AuthError::HashError(e.to_string()))?;
    Ok(hash.to_string())
}

/// Verify a plaintext password against a stored PHC-format hash.
///
/// Returns `Ok(true)` if the password matches, `Ok(false)` if not.
pub fn verify_password(plain: &str, hash: &str) -> AuthResult<bool> {
    let parsed = PasswordHash::new(hash).map_err(|e| AuthError::HashError(e.to_string()))?;
    Ok(Argon2::default()
        .verify_password(plain.as_bytes(), &parsed)
        .is_ok())
}

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

    #[test]
    fn test_hash_and_verify() {
        let hash = hash_password("test123").unwrap();
        assert!(
            verify_password("test123", &hash).unwrap(),
            "Correct password should verify"
        );
        assert!(
            !verify_password("wrong", &hash).unwrap(),
            "Wrong password should not verify"
        );
    }

    #[test]
    fn test_hash_is_unique() {
        let hash1 = hash_password("same_password").unwrap();
        let hash2 = hash_password("same_password").unwrap();
        assert_ne!(
            hash1, hash2,
            "Two hashes of the same password should differ (different salts)"
        );
    }
}
