use nowhub_plugin_rust::jws::verify_ed25519_pem;
use base64::Engine;
use ed25519_dalek::pkcs8::EncodePublicKey;
use ed25519_dalek::SigningKey;
use ed25519_dalek::Signer;
use rand::rngs::OsRng;

const B64URL: base64::engine::general_purpose::GeneralPurpose =
    base64::engine::general_purpose::URL_SAFE_NO_PAD;

fn sign_compact_jws_ed25519(
    signing_key: &SigningKey,
    kid: &str,
    payload: &serde_json::Value,
) -> String {
    let header = serde_json::json!({
        "alg": "EdDSA",
        "kid": kid,
        "typ": "axis-pubkeys+jws"
    });
    let header_b64 = B64URL.encode(serde_json::to_vec(&header).unwrap());
    let payload_b64 = B64URL.encode(serde_json::to_vec(payload).unwrap());
    let signing_input = format!("{header_b64}.{payload_b64}");
    let signature = signing_key.sign(signing_input.as_bytes());
    format!("{signing_input}.{}", B64URL.encode(signature.to_bytes()))
}

#[test]
fn verifies_a_valid_ed25519_jws() {
    let signing_key = SigningKey::generate(&mut OsRng);
    let verifying_key = signing_key.verifying_key();
    let public_pem = verifying_key.to_public_key_pem(Default::default()).unwrap();

    let payload = serde_json::json!({ "tenant_id": "tenant_axis", "keys": [] });
    let compact = sign_compact_jws_ed25519(&signing_key, "axis-root-test", &payload);

    let verified = verify_ed25519_pem(&compact, &public_pem).expect("should verify");
    assert_eq!(verified.header.alg, "EdDSA");
    assert_eq!(verified.header.kid.as_deref(), Some("axis-root-test"));
    let decoded: serde_json::Value = serde_json::from_slice(&verified.payload).unwrap();
    assert_eq!(decoded["tenant_id"], "tenant_axis");
}

#[test]
fn rejects_signature_signed_by_a_different_key() {
    let signer = SigningKey::generate(&mut OsRng);
    let imposter = SigningKey::generate(&mut OsRng);
    let public_pem = imposter
        .verifying_key()
        .to_public_key_pem(Default::default())
        .unwrap();

    let payload = serde_json::json!({});
    let compact = sign_compact_jws_ed25519(&signer, "axis-root-test", &payload);

    let result = verify_ed25519_pem(&compact, &public_pem);
    assert!(result.is_err());
}
