//! SC-7 — Allowlist drops non-paired senders BEFORE any parse.
//!
//! An inbound row whose `handle.id` is NOT in the allowlist results in zero
//! resolve calls, zero sends, and zero parse invocations — the row is dropped
//! BEFORE the parser (asserted via the orchestrator's parse-call counter
//! staying 0).
//!
//! Edge: in a mixed batch, only the allowlisted row is parsed (the filter is
//! per-row, not all-or-nothing).

mod messaging_harness;
use messaging_harness::{extract_code, inbound, Harness, PAIRED};

#[tokio::test]
async fn non_allowlisted_sender_dropped_before_parse() {
    let h = Harness::enabled_paired();
    let id = h.seed_fire_and_return("transfer funds").await;
    h.orch.observe_and_notify().await; // prompt the paired handle
    let sends_after_prompt = h.spy.count();

    // A row from a sender NOT on the allowlist, with text that WOULD resolve.
    h.orch
        .handle_inbound(&inbound("+19998887777", "approve", 1))
        .await;

    assert_eq!(
        h.orch.parse_call_count(),
        0,
        "a non-allowlisted row must be dropped BEFORE the parser (parse count 0)"
    );
    assert!(
        !h.is_resolved(&id).await,
        "no resolve from a non-allowlisted sender"
    );
    assert_eq!(
        h.spy.count(),
        sends_after_prompt,
        "no send (disambiguation or otherwise) for a dropped row"
    );
}

#[tokio::test]
async fn mixed_batch_only_allowlisted_row_parsed() {
    let h = Harness::enabled_paired();
    let id = h.seed_fire_and_return("publish the post").await;
    h.orch.observe_and_notify().await;
    let code = extract_code(&h.spy.calls()[0].1).unwrap();

    // Non-allowlisted row first, then the allowlisted approve.
    h.orch
        .handle_inbound(&inbound("+19998887777", "approve", 1))
        .await;
    assert_eq!(
        h.orch.parse_call_count(),
        0,
        "the non-allowlisted row did not reach the parser"
    );

    h.orch
        .handle_inbound(&inbound(PAIRED, &format!("{code} approve"), 2))
        .await;
    assert_eq!(
        h.orch.parse_call_count(),
        1,
        "only the allowlisted row reached the parser"
    );
    assert!(
        h.is_resolved(&id).await,
        "the allowlisted row resolved its approval"
    );
}

#[tokio::test]
async fn feature_off_no_parse_even_for_allowlisted() {
    let h = Harness::disabled();
    // Even an allowlisted-looking handle is dropped when the feature is OFF.
    h.orch
        .handle_inbound(&inbound(PAIRED, "approve", 1))
        .await;
    assert_eq!(
        h.orch.parse_call_count(),
        0,
        "feature OFF ⇒ no parse, no resolve, no send"
    );
    assert_eq!(h.spy.count(), 0);
}
