use ed25519_dalek::SigningKey;
use ontoref_types::{
    canonical,
    hlc::Hlc,
    op_id::OpId,
    operation::{OpBody, OpPayload, Operation},
    signature::PublicKey,
};

fn signing_key() -> SigningKey {
    SigningKey::from_bytes(&[7u8; 32])
}

fn sample() -> Operation {
    let key = signing_key();
    let body = OpBody {
        actor: PublicKey::from_signing_key(&key),
        parents: vec![],
        payload: OpPayload::Noop {
            label: "g1-fixture".into(),
        },
        timestamp: Hlc::genesis(),
    };
    Operation::sign(body, &key)
}

#[test]
fn canonical_encoding_is_deterministic() {
    let op = sample();
    let a = canonical::encode(&op).unwrap();
    let b = canonical::encode(&op).unwrap();
    assert_eq!(
        a, b,
        "two encodes of the same op must produce identical bytes"
    );
    assert_eq!(op.id(), OpId::from_bytes(&a));
}

#[test]
fn round_trip_preserves_id() {
    let op = sample();
    let encoded = canonical::encode(&op).unwrap();
    let decoded: Operation = canonical::decode(&encoded).unwrap();
    assert_eq!(op, decoded);
    assert_eq!(op.id(), decoded.id());
}

#[test]
fn signature_verifies() {
    let op = sample();
    op.verify_signature()
        .expect("signature must verify under the actor's public key");
}

#[test]
fn tampered_body_fails_verification() {
    let mut op = sample();
    match &mut op.body.payload {
        OpPayload::Noop { label } => label.push_str("-tampered"),
        other => panic!("g1 fixture should be a Noop, got {other:?}"),
    }
    assert!(
        op.verify_signature().is_err(),
        "tampering with the body must invalidate the signature"
    );
}
