//! Tests for the disjoint-authority invariant
//! (`verifier.witness.authority_overlap`).

mod common;

use chrono::{Duration, Utc};
use cortex_verifier::{
    verify, AuthorityDomain, VerifiedTrustState, WitnessClass, WITNESS_AUTHORITY_OVERLAP,
};

use crate::common::{
    authority_grade_input, force_authority_domain, full_witness_set, sample_evidence_digest,
    signed_witness, Kind,
};

#[test]
fn two_witnesses_sharing_authority_domain_break_disjointness() {
    let digest = sample_evidence_digest();
    let now = Utc::now();
    let mut witnesses = full_witness_set(&digest, now);
    // Force witness index 1 (external anchor) onto the local_signed_ledger
    // domain so two witnesses share `local_signed_ledger`.
    force_authority_domain(&mut witnesses[1], 2, AuthorityDomain::LocalSignedLedger);

    let state = verify(
        &authority_grade_input(Kind::ReleaseReadiness),
        &witnesses,
        now,
        Duration::seconds(86_400),
    );

    match state {
        VerifiedTrustState::Broken { edge, .. } => {
            assert_eq!(edge.invariant, WITNESS_AUTHORITY_OVERLAP);
            assert!(
                edge.detail.contains("local_signed_ledger"),
                "edge detail should name colliding domain: {}",
                edge.detail
            );
        }
        other => panic!("expected Broken(authority_overlap), got {other:?}"),
    }
}

#[test]
fn witness_class_with_mismatched_domain_is_authority_overlap() {
    let digest = sample_evidence_digest();
    let now = Utc::now();
    let mut witness = signed_witness(
        9,
        WitnessClass::RemoteCiConclusion,
        cortex_verifier::WitnessTier::ThirdParty,
        &digest,
        now,
    );
    // Class is RemoteCi but we claim the LocalSignedLedger domain.
    force_authority_domain(&mut witness, 9, AuthorityDomain::LocalSignedLedger);

    let state = verify(
        &authority_grade_input(Kind::ReleaseReadiness),
        &[witness],
        now,
        Duration::seconds(86_400),
    );

    match state {
        VerifiedTrustState::Broken { edge, .. } => {
            assert_eq!(edge.invariant, WITNESS_AUTHORITY_OVERLAP);
            assert!(edge.detail.contains("remote_ci_provider"));
        }
        other => panic!("expected Broken(authority_overlap), got {other:?}"),
    }
}

#[test]
fn full_witness_set_has_disjoint_authority_domains() {
    let digest = sample_evidence_digest();
    let now = Utc::now();
    let witnesses = full_witness_set(&digest, now);
    let mut domains: Vec<_> = witnesses.iter().map(|w| w.authority_domain).collect();
    domains.sort_by_key(|d| d.wire_str());
    domains.dedup();
    assert_eq!(domains.len(), 4, "all four domains must be distinct");
}
