use bucketwarden_auth::{
    sign_hs256_jwt, AuthError, AuthStore, IdentityProvider, JwtClaims, OidcProvider,
};

const NOW: u64 = 1_700_000_000;

#[test]
fn oidc_provider_verifies_hs256_jwt_issuer_audience_kid_and_subject() {
    let provider = OidcProvider::hs256(
        "oidc-main",
        "https://issuer.example",
        "bucketwarden",
        "key-1",
        "shared-secret",
        "oidc:",
    );
    let token = token("alice", NOW + 60, "shared-secret");

    let subject = provider.verify_subject(&token, NOW).expect("subject");

    assert_eq!(subject, "alice");
    assert_eq!(provider.principal_id(&subject), "oidc:alice");
}

#[test]
fn oidc_provider_rejects_expired_or_wrongly_signed_jwt() {
    let provider = OidcProvider::hs256(
        "oidc-main",
        "https://issuer.example",
        "bucketwarden",
        "key-1",
        "shared-secret",
        "oidc:",
    );

    assert_eq!(
        provider.verify_subject(&token("alice", NOW - 1, "shared-secret"), NOW),
        Err(AuthError::WebIdentityTokenExpired)
    );
    assert!(matches!(
        provider.verify_subject(&token("alice", NOW + 60, "wrong-secret"), NOW),
        Err(AuthError::InvalidWebIdentityToken(_))
    ));
}

#[test]
fn auth_store_registers_external_provider_without_implementing_oob_providers() {
    let mut store = AuthStore::new();
    store.upsert_identity_provider(IdentityProvider::Oidc(OidcProvider::hs256(
        "oidc-main",
        "https://issuer.example",
        "bucketwarden",
        "key-1",
        "shared-secret",
        "oidc:",
    )));

    assert_eq!(store.identity_provider_count(), 1);
    assert!(store.identity_provider("oidc-main").is_some());
    assert!(store.identity_provider("kerberos").is_none());
    assert!(store.identity_provider("keystone").is_none());
    assert!(store.identity_provider("external-iam").is_none());
}

fn token(subject: &str, exp: u64, secret: &str) -> String {
    sign_hs256_jwt(
        Some("key-1"),
        &JwtClaims {
            iss: "https://issuer.example".to_string(),
            sub: subject.to_string(),
            aud: vec!["bucketwarden".to_string()],
            exp: Some(exp),
            iat: Some(NOW),
        },
        secret.as_bytes(),
    )
    .expect("token")
}
