//! Connectivity test for the runtime n0-relay toggle (peat-flutter relay feature).
//!
//! Builds two iroh endpoints with `enable_n0_relay = true` (the runtime arg
//! added to `IrohTransport::from_seed_with_discovery_at_addr`, which selects
//! `presets::N0`) and establishes a direct QUIC connection between them on
//! loopback. This proves that enabling the n0 hosted relay pool does **not**
//! break ordinary connectivity — the endpoint still binds, accepts, and dials.
//!
//! This is hermetic and runs in normal CI: the client dials the server by its
//! already-known loopback address, so iroh short-circuits address resolution
//! and never needs to reach n0's relay/DNS infrastructure.
//!
//! NON-GOAL: this does not exercise relay *transit*. Two endpoints on one host
//! share loopback and hole-punch a direct path — they never actually relay.
//! A genuine relay-transit check needs two hosts behind separate NATs with live
//! n0 reachability, which can't be hermetic; that stays the manual two-device
//! acceptance test (toggle "Enable Internet Relay" in the example app on two
//! devices on different networks and watch the water counter converge).

#![cfg(feature = "automerge-backend")]

use peat_mesh::network::IrohTransport;
use std::sync::Arc;
use std::time::Duration;

#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn n0_relay_endpoints_connect_directly() {
    let bind: std::net::SocketAddr = "127.0.0.1:0".parse().unwrap();

    // Both endpoints opt into the n0 hosted relay pool (presets::N0).
    let server = Arc::new(
        IrohTransport::from_seed_with_discovery_at_addr("relay-conn/server", bind, true)
            .await
            .expect("server endpoint must bind with presets::N0"),
    );
    let client = IrohTransport::from_seed_with_discovery_at_addr("relay-conn/client", bind, true)
        .await
        .expect("client endpoint must bind with presets::N0");

    // Server must be accepting for the dial to complete.
    server
        .start_accept_loop()
        .expect("server accept loop must start");

    // The server's bound loopback address — hand it to the client directly so
    // iroh dials the known path (no n0 DNS/relay resolution involved).
    let server_addr = server.endpoint_addr();
    assert!(
        !server_addr.addrs.is_empty(),
        "server must have bound at least one loopback socket; got empty EndpointAddr"
    );

    let conn = tokio::time::timeout(Duration::from_secs(15), client.connect(server_addr))
        .await
        .expect("connect timed out on loopback — an N0-preset endpoint should still dial directly")
        .expect("connect returned Err")
        .expect("connect returned None (no connection established)");

    assert_eq!(
        conn.remote_id(),
        server.endpoint_id(),
        "connected to the wrong peer"
    );

    server.close().await.ok();
    client.close().await.ok();
}
