//! Integration test for `MdnsDiscovery::advertise_with_addr` (peat#897).
//!
//! Two `MdnsDiscovery` instances on the same host advertise on
//! **loopback** addresses and must discover each other end-to-end.
//!
//! Closed by the mdns_sd 0.19 upgrade: the daemon now exposes
//! `IfKind::LoopbackV4` / `IfKind::LoopbackV6` and peat-mesh's
//! `MdnsDiscovery::start()` calls `enable_interface` for both, so the
//! daemon joins the loopback multicast group on top of its default
//! non-loopback interface set. With both daemons on the same host
//! listening on `lo` plus their default interfaces, announces published
//! at `127.0.0.1:PORT` reach the other daemon's browse path.
//!
//! `#[ignore]` is retained as a CI guardrail — GitHub Actions and most
//! containerized CI runners block multicast joins, so this test needs
//! bare-metal hardware (or a runner with multicast enabled). Locally:
//!
//! ```sh
//! cargo test --test mdns_advertise_with_addr -- --ignored
//! ```

use peat_mesh::discovery::{DiscoveryStrategy, MdnsDiscovery};
use std::time::{Duration, Instant};

#[tokio::test]
#[ignore = "requires multicast in CI; run with --ignored on bare metal"]
async fn two_nodes_mutual_loopback_discovery() {
    let mut a = MdnsDiscovery::new().expect("create MdnsDiscovery A");
    let mut b = MdnsDiscovery::new().expect("create MdnsDiscovery B");

    a.start().await.expect("start A");
    b.start().await.expect("start B");

    a.advertise_with_addr("node-A", "127.0.0.1:39001".parse().unwrap(), None)
        .expect("advertise A");
    b.advertise_with_addr("node-B", "127.0.0.1:39002".parse().unwrap(), None)
        .expect("advertise B");

    // mDNS announce + browse round-trip is typically 1-3s. Allow up to 10s
    // before failing, polling every 250ms for cheaper failure feedback.
    let deadline = Instant::now() + Duration::from_secs(10);
    loop {
        let a_peers = a.discovered_peers().await;
        let b_peers = b.discovered_peers().await;

        let a_sees_b = a_peers.iter().any(|p| {
            p.node_id == "node-B"
                && p.addresses
                    .iter()
                    .any(|s| s.ip().is_loopback() && s.port() == 39002)
        });
        let b_sees_a = b_peers.iter().any(|p| {
            p.node_id == "node-A"
                && p.addresses
                    .iter()
                    .any(|s| s.ip().is_loopback() && s.port() == 39001)
        });

        if a_sees_b && b_sees_a {
            // Both sides observe the other at the exact loopback `IP:port`
            // we advertised — the peat#897 regression gate is closed.
            return;
        }
        if Instant::now() > deadline {
            panic!(
                "timed out waiting for mutual loopback discovery: a_sees_b={a_sees_b} b_sees_a={b_sees_a}\nA peers: {a_peers:?}\nB peers: {b_peers:?}"
            );
        }
        tokio::time::sleep(Duration::from_millis(250)).await;
    }
}
