use std::sync::Arc;
use std::time::Duration;

use base64::Engine as _;

use crate::{
    common::{
        PeerId,
        error::Error,
        global_ctx::{
            NetworkIdentity, TrustedKeySource,
            tests::{get_mock_global_ctx, get_mock_global_ctx_with_network},
        },
        stats_manager::{LabelSet, LabelType, MetricName},
    },
    proto::api::instance::TrustedKeySourcePb,
    tunnel::{
        common::tests::wait_for_condition,
        packet_def::{PacketType, ZCPacket},
        ring::create_ring_tunnel_pair,
    },
};

use super::{
    create_packet_recv_chan,
    peer_conn::tests::set_secure_mode_cfg,
    peer_manager::{PeerManager, RouteAlgoType},
    peer_map::PeerMap,
    peer_session::{PeerSession, PeerSessionStore, SessionKey},
    relay_peer_map::RelayPeerMap,
    route_trait::NextHopPolicy,
};

pub async fn create_mock_peer_manager() -> Arc<PeerManager> {
    let (s, _r) = create_packet_recv_chan();
    let peer_mgr = Arc::new(PeerManager::new(
        RouteAlgoType::Ospf,
        get_mock_global_ctx(),
        s,
    ));
    peer_mgr.run().await.unwrap();
    peer_mgr
}

pub async fn create_mock_peer_manager_with_name(network_name: String) -> Arc<PeerManager> {
    let (s, _r) = create_packet_recv_chan();
    let g =
        get_mock_global_ctx_with_network(Some(NetworkIdentity::new(network_name, "".to_string())));
    let peer_mgr = Arc::new(PeerManager::new(RouteAlgoType::Ospf, g, s));
    peer_mgr.run().await.unwrap();
    peer_mgr
}

pub async fn create_mock_peer_manager_secure(
    network_name: String,
    network_secret: String,
) -> Arc<PeerManager> {
    let (s, _r) = create_packet_recv_chan();
    let g =
        get_mock_global_ctx_with_network(Some(NetworkIdentity::new(network_name, network_secret)));
    set_secure_mode_cfg(&g, true);
    let peer_mgr = Arc::new(PeerManager::new(RouteAlgoType::Ospf, g, s));
    peer_mgr.run().await.unwrap();
    peer_mgr
}

fn set_private_mode(peer_mgr: &PeerManager, enabled: bool) {
    let global_ctx = peer_mgr.get_global_ctx();
    let mut flags = global_ctx.get_flags();
    flags.private_mode = enabled;
    global_ctx.set_flags(flags);
}

async fn connect_client_and_server(
    client: Arc<PeerManager>,
    server: Arc<PeerManager>,
) -> (Result<(), Error>, Result<(), Error>) {
    let (client_ring, server_ring) = create_ring_tunnel_pair();
    tokio::join!(
        {
            let client = client.clone();
            async move {
                client.add_client_tunnel(client_ring, false).await?;
                Ok(())
            }
        },
        {
            let server = server.clone();
            async move { server.add_tunnel_as_server(server_ring, true).await }
        }
    )
}

async fn wait_for_foreign_network(server: Arc<PeerManager>, network_name: &'static str) {
    wait_for_condition(
        || {
            let server = server.clone();
            async move {
                server
                    .get_foreign_network_manager()
                    .list_foreign_networks()
                    .await
                    .foreign_networks
                    .contains_key(network_name)
            }
        },
        Duration::from_secs(10),
    )
    .await;
}

async fn wait_for_foreign_network_peer_count_at_least(
    server: Arc<PeerManager>,
    network_name: &'static str,
    min_peer_count: usize,
) {
    wait_for_condition(
        || {
            let server = server.clone();
            async move {
                server
                    .get_foreign_network_manager()
                    .list_foreign_networks()
                    .await
                    .foreign_networks
                    .get(network_name)
                    .map(|entry| entry.peers.len() >= min_peer_count)
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;
}

async fn wait_for_public_peers_empty(client: Arc<PeerManager>) {
    wait_for_condition(
        || {
            let client = client.clone();
            async move {
                client
                    .get_foreign_network_client()
                    .list_public_peers()
                    .await
                    .is_empty()
            }
        },
        Duration::from_secs(5),
    )
    .await;
}

pub async fn connect_peer_manager(client: Arc<PeerManager>, server: Arc<PeerManager>) {
    let (a_ring, b_ring) = create_ring_tunnel_pair();
    let a_mgr_copy = client;
    tokio::spawn(async move {
        a_mgr_copy.add_client_tunnel(a_ring, false).await.unwrap();
    });
    let b_mgr_copy = server;
    tokio::spawn(async move {
        b_mgr_copy.add_tunnel_as_server(b_ring, true).await.unwrap();
    });
}

pub async fn wait_route_appear_with_cost(
    peer_mgr: Arc<PeerManager>,
    node_id: PeerId,
    cost: Option<i32>,
) -> Result<(), Error> {
    let now = std::time::Instant::now();
    while now.elapsed().as_secs() < 5 {
        let route = peer_mgr.list_routes().await;
        if route
            .iter()
            .any(|r| r.peer_id == node_id && (cost.is_none() || r.cost == cost.unwrap()))
        {
            return Ok(());
        }
        tokio::time::sleep(std::time::Duration::from_millis(50)).await;
    }
    Err(Error::NotFound)
}

pub async fn wait_route_appear(
    peer_mgr: Arc<PeerManager>,
    target_peer: Arc<PeerManager>,
) -> Result<(), Error> {
    wait_route_appear_with_cost(peer_mgr.clone(), target_peer.my_peer_id(), None).await?;
    wait_route_appear_with_cost(target_peer, peer_mgr.my_peer_id(), None).await
}

fn metric_value(peer_mgr: &PeerManager, metric: MetricName, network_name: &str) -> u64 {
    peer_mgr
        .get_global_ctx()
        .stats_manager()
        .get_metric(
            metric,
            &LabelSet::new().with_label_type(LabelType::NetworkName(network_name.to_string())),
        )
        .map(|metric| metric.value)
        .unwrap_or(0)
}

#[tokio::test]
async fn foreign_mgr_stress_test() {
    const FOREIGN_NETWORK_COUNT: i32 = 20;
    const PEER_PER_NETWORK: i32 = 3;
    const PUBLIC_PEER_COUNT: i32 = 3;

    let mut public_peers = Vec::new();
    for _ in 0..PUBLIC_PEER_COUNT {
        public_peers.push(create_mock_peer_manager().await);
    }
    connect_peer_manager(public_peers[0].clone(), public_peers[1].clone()).await;
    connect_peer_manager(public_peers[0].clone(), public_peers[2].clone()).await;
    connect_peer_manager(public_peers[1].clone(), public_peers[2].clone()).await;

    let mut foreigns = Vec::new();

    for i in 0..FOREIGN_NETWORK_COUNT {
        let mut peers = Vec::new();

        let name = format!("foreign-network-test-{}", i);

        for _ in 0..PEER_PER_NETWORK {
            let mgr = create_mock_peer_manager_with_name(name.clone()).await;
            let public_peer_idx = rand::random::<usize>() % public_peers.len();
            connect_peer_manager(mgr.clone(), public_peers[public_peer_idx].clone()).await;
            peers.push(mgr);
        }

        foreigns.push(peers);
    }

    for _ in 0..5 {
        for i in 0..PUBLIC_PEER_COUNT {
            let p = public_peers[i as usize].clone();
            println!(
                "public peer {} routes: {:?}, global_foreign_network: {:?}, peers: {:?}",
                i,
                p.list_routes().await,
                p.list_global_foreign_network().await.foreign_networks.len(),
                p.get_peer_map().list_peers()
            );
        }
        tokio::time::sleep(std::time::Duration::from_secs(1)).await;

        let new_peer = create_mock_peer_manager().await;
        connect_peer_manager(new_peer.clone(), public_peers[0].clone()).await;
        while let Err(e) = wait_route_appear(public_peers[1].clone(), new_peer.clone()).await {
            println!("wait route ret: {:?}", e);
        }
    }
}

#[tokio::test]
async fn relay_peer_map_secure_session_decrypt() {
    let (s, _r) = create_packet_recv_chan();
    let ctx = get_mock_global_ctx_with_network(Some(NetworkIdentity::new(
        "net1".to_string(),
        "sec1".to_string(),
    )));
    set_secure_mode_cfg(&ctx, true);
    let peer_map = Arc::new(PeerMap::new(s, ctx.clone(), 10));
    let store = Arc::new(PeerSessionStore::new());
    let relay_map = RelayPeerMap::new(peer_map, None, ctx.clone(), 10, store.clone());

    let algo = ctx.get_flags().encryption_algorithm.clone();
    let root_key = [7u8; 32];
    let session = Arc::new(PeerSession::new(
        20,
        root_key,
        1,
        1,
        algo.clone(),
        algo.clone(),
        None,
    ));
    let key = SessionKey::new(ctx.get_network_identity().network_name, 20);
    store.insert_session(key.clone(), session.clone());

    relay_map
        .ensure_session(20, NextHopPolicy::LeastHop)
        .await
        .unwrap();
    assert!(relay_map.has_session(20));

    let mut packet = ZCPacket::new_with_payload(b"relay-hello");
    packet.fill_peer_manager_hdr(20, 10, PacketType::Data as u8);
    session.encrypt_payload(20, 10, &mut packet).unwrap();
    assert!(relay_map.decrypt_if_needed(&mut packet).await.unwrap());
    assert_eq!(packet.payload(), b"relay-hello");
}

#[tokio::test]
async fn private_mode_allows_foreign_network_with_same_secret() {
    let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
    let client =
        create_mock_peer_manager_secure("tenant-a".to_string(), "shared".to_string()).await;
    set_private_mode(&server, true);

    let (client_ret, server_ret) = connect_client_and_server(client, server.clone()).await;

    assert!(client_ret.is_ok(), "client should connect in private mode");
    assert!(
        server_ret.is_ok(),
        "server should accept foreign network with matching secret: {:?}",
        server_ret
    );
    wait_for_foreign_network(server, "tenant-a").await;
}

#[tokio::test]
async fn private_mode_rejects_foreign_network_with_different_secret() {
    let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
    let client = create_mock_peer_manager_secure("tenant-a".to_string(), "other".to_string()).await;
    set_private_mode(&server, true);

    let (client_ret, server_ret) = connect_client_and_server(client.clone(), server.clone()).await;

    assert!(
        server_ret.is_err(),
        "server should reject foreign network with mismatched secret in private mode"
    );
    let _ = client_ret;
    wait_for_public_peers_empty(client).await;
    assert!(
        server
            .get_foreign_network_manager()
            .list_foreign_networks()
            .await
            .foreign_networks
            .is_empty()
    );
}

#[tokio::test]
async fn private_mode_allows_trusted_foreign_credential() {
    let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
    let admin = create_mock_peer_manager_secure("tenant-a".to_string(), "shared".to_string()).await;
    set_private_mode(&server, true);

    let (_cred_id, cred_secret) = admin
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(vec![], false, vec![], Duration::from_secs(3600));

    let privkey_bytes: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let private = x25519_dalek::StaticSecret::from(privkey_bytes);
    let public = x25519_dalek::PublicKey::from(&private);
    let credential = create_mock_peer_manager_credential("tenant-a".to_string(), &private).await;

    connect_peer_manager(admin.clone(), server.clone()).await;
    wait_for_condition(
        || {
            let server = server.clone();
            let pubkey = public.as_bytes().to_vec();
            async move {
                server
                    .get_foreign_network_manager()
                    .list_foreign_networks_with_options(true)
                    .await
                    .foreign_networks
                    .get("tenant-a")
                    .map(|entry| {
                        entry.trusted_keys.iter().any(|trusted_key| {
                            trusted_key.pubkey == pubkey
                                && trusted_key.source == TrustedKeySourcePb::OspfCredential as i32
                        })
                    })
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    let (client_ret, server_ret) = connect_client_and_server(credential, server.clone()).await;

    assert!(
        client_ret.is_ok(),
        "trusted foreign credential client should connect in private mode"
    );
    assert!(
        server_ret.is_ok(),
        "server should allow trusted foreign credential in private mode: {:?}",
        server_ret
    );
    wait_for_foreign_network_peer_count_at_least(server, "tenant-a", 2).await;
}

#[tokio::test]
async fn private_mode_rejects_untrusted_foreign_credential() {
    let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
    let admin = create_mock_peer_manager_secure("tenant-a".to_string(), "shared".to_string()).await;
    set_private_mode(&server, true);

    let random_private = x25519_dalek::StaticSecret::random_from_rng(rand::rngs::OsRng);
    let unknown_credential =
        create_mock_peer_manager_credential("tenant-a".to_string(), &random_private).await;

    connect_peer_manager(admin.clone(), server.clone()).await;
    wait_for_foreign_network(server.clone(), "tenant-a").await;

    let (client_ret, server_ret) =
        connect_client_and_server(unknown_credential, server.clone()).await;

    let _ = client_ret;
    assert!(
        server_ret.is_err(),
        "server should reject untrusted foreign credential in private mode"
    );
    wait_for_condition(
        || {
            let server = server.clone();
            async move {
                server
                    .get_foreign_network_manager()
                    .list_foreign_networks()
                    .await
                    .foreign_networks
                    .get("tenant-a")
                    .map(|entry| entry.peers.len() == 1)
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;
}

#[tokio::test]
async fn relay_peer_map_retry_backoff_and_evict() {
    let (s, _r) = create_packet_recv_chan();
    let ctx_secure = get_mock_global_ctx();
    set_secure_mode_cfg(&ctx_secure, true);
    let peer_map = Arc::new(PeerMap::new(s, ctx_secure.clone(), 10));
    let relay_map = RelayPeerMap::new(
        peer_map,
        None,
        ctx_secure.clone(),
        10,
        Arc::new(PeerSessionStore::new()),
    );

    let ret = relay_map
        .handshake_session(20, NextHopPolicy::LeastHop, None)
        .await;
    assert!(ret.is_err());
    assert!(relay_map.failure_count(20).unwrap_or(0) >= 1);
    assert!(relay_map.is_backoff_active(20));

    let (s2, _r2) = create_packet_recv_chan();
    let ctx_plain = get_mock_global_ctx();
    let peer_map_plain = Arc::new(PeerMap::new(s2, ctx_plain.clone(), 30));
    let relay_map_plain = RelayPeerMap::new(
        peer_map_plain,
        None,
        ctx_plain.clone(),
        30,
        Arc::new(PeerSessionStore::new()),
    );

    let mut pkt = ZCPacket::new_with_payload(b"evict");
    pkt.fill_peer_manager_hdr(30, 40, PacketType::Data as u8);
    let _ = relay_map_plain
        .send_msg(pkt, 40, NextHopPolicy::LeastHop)
        .await;
    assert!(relay_map_plain.has_state(40));
    relay_map_plain.evict_idle_sessions(Duration::from_millis(0));
    assert!(!relay_map_plain.has_state(40));
}

#[tokio::test]
async fn relay_peer_map_pending_packet_buffer() {
    // Verify that packets sent during handshake are buffered (not dropped),
    // and flushed after handshake completes.
    let (s, _r) = create_packet_recv_chan();
    let ctx = get_mock_global_ctx_with_network(Some(NetworkIdentity::new(
        "net1".to_string(),
        "sec1".to_string(),
    )));
    set_secure_mode_cfg(&ctx, true);
    let peer_map = Arc::new(PeerMap::new(s, ctx.clone(), 10));
    let store = Arc::new(PeerSessionStore::new());
    let relay_map = RelayPeerMap::new(peer_map, None, ctx.clone(), 10, store.clone());

    // Send multiple packets while no session exists (handshake will fail, but packets should be buffered)
    for i in 0..5u8 {
        let mut pkt = ZCPacket::new_with_payload(&[i]);
        pkt.fill_peer_manager_hdr(10, 20, PacketType::Data as u8);
        let _ = relay_map.send_msg(pkt, 20, NextHopPolicy::LeastHop).await;
    }

    // Verify packets were buffered
    assert_eq!(
        relay_map
            .pending_packets
            .get(&20)
            .map(|v| v.len())
            .unwrap_or(0),
        5,
        "5 packets should be buffered during handshake"
    );

    // Verify buffer respects capacity limit
    for i in 0..50u8 {
        let mut pkt = ZCPacket::new_with_payload(&[i]);
        pkt.fill_peer_manager_hdr(10, 20, PacketType::Data as u8);
        let _ = relay_map.send_msg(pkt, 20, NextHopPolicy::LeastHop).await;
    }

    let buffered = relay_map
        .pending_packets
        .get(&20)
        .map(|v| v.len())
        .unwrap_or(0);
    assert!(
        buffered <= 32,
        "buffer should not exceed MAX_PENDING_PACKETS_PER_PEER, got {buffered}"
    );

    // Verify remove_peer clears pending packets
    relay_map.remove_peer(20);
    assert_eq!(
        relay_map
            .pending_packets
            .get(&20)
            .map(|v| v.len())
            .unwrap_or(0),
        0,
        "pending packets should be cleared on peer removal"
    );
}

#[tokio::test]
async fn relay_peer_map_pending_packets_flushed_on_handshake_success() {
    // Test that pending packets are flushed after handshake succeeds.
    // We pre-populate the buffer, then run handshake, and verify it's cleared.
    let peer_a = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_b = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_c = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;

    connect_peer_manager(peer_a.clone(), peer_b.clone()).await;
    connect_peer_manager(peer_b.clone(), peer_c.clone()).await;

    let peer_a_id = peer_a.my_peer_id();
    let peer_c_id = peer_c.my_peer_id();

    // Wait for routes to propagate
    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            let peer_c = peer_c.clone();
            async move { wait_route_appear(peer_a.clone(), peer_c).await.is_ok() }
        },
        Duration::from_secs(10),
    )
    .await;

    // Wait for noise_static_pubkey to be available on both sides
    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            async move {
                peer_a
                    .get_peer_map()
                    .get_route_peer_info(peer_c_id)
                    .await
                    .map(|info| !info.noise_static_pubkey.is_empty())
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    let relay_a = peer_a.get_relay_peer_map();

    // Pre-populate pending packets buffer (simulating what send_msg does during handshake)
    for i in 0..3u8 {
        let mut pkt = ZCPacket::new_with_payload(&[i]);
        pkt.fill_peer_manager_hdr(peer_a_id, peer_c_id, PacketType::Data as u8);
        relay_a
            .pending_packets
            .entry(peer_c_id)
            .or_default()
            .push((pkt, NextHopPolicy::LeastHop));
    }

    assert_eq!(
        relay_a
            .pending_packets
            .get(&peer_c_id)
            .map(|v| v.len())
            .unwrap_or(0),
        3,
        "3 packets should be in the buffer"
    );

    // Run handshake — on success it should flush the buffer
    relay_a
        .handshake_session(peer_c_id, NextHopPolicy::LeastHop, None)
        .await
        .unwrap();

    // Verify session established and buffer cleared
    assert!(relay_a.has_session(peer_c_id));
    assert_eq!(
        relay_a
            .pending_packets
            .get(&peer_c_id)
            .map(|v| v.len())
            .unwrap_or(0),
        0,
        "pending packets should be flushed after successful handshake"
    );
}

#[tokio::test]
async fn relay_peer_map_real_link_handshake_success() {
    let peer_a = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_b = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_c = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;

    connect_peer_manager(peer_a.clone(), peer_b.clone()).await;
    connect_peer_manager(peer_b.clone(), peer_c.clone()).await;

    let peer_a_id = peer_a.my_peer_id();
    let peer_b_id = peer_b.my_peer_id();
    let peer_c_id = peer_c.my_peer_id();
    let a_control_tx_before = metric_value(&peer_a, MetricName::TrafficControlBytesTx, "net1");
    let a_control_rx_before = metric_value(&peer_a, MetricName::TrafficControlBytesRx, "net1");
    let c_control_tx_before = metric_value(&peer_c, MetricName::TrafficControlBytesTx, "net1");
    let c_control_rx_before = metric_value(&peer_c, MetricName::TrafficControlBytesRx, "net1");

    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            let peer_c = peer_c.clone();
            async move { wait_route_appear(peer_a.clone(), peer_c).await.is_ok() }
        },
        Duration::from_secs(10),
    )
    .await;

    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            async move {
                peer_a
                    .get_peer_map()
                    .get_gateway_peer_id(peer_c_id, NextHopPolicy::LeastHop)
                    .await
                    == Some(peer_b_id)
            }
        },
        Duration::from_secs(5),
    )
    .await;

    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            async move {
                peer_a
                    .get_peer_map()
                    .get_route_peer_info(peer_c_id)
                    .await
                    .map(|info| !info.noise_static_pubkey.is_empty())
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    let relay_a = peer_a.get_relay_peer_map();
    let relay_c = peer_c.get_relay_peer_map();

    relay_a
        .handshake_session(peer_c_id, NextHopPolicy::LeastHop, None)
        .await
        .unwrap();

    wait_for_condition(
        || {
            let relay_a = relay_a.clone();
            async move { relay_a.has_session(peer_c_id) }
        },
        Duration::from_secs(5),
    )
    .await;

    wait_for_condition(
        || {
            let relay_c = relay_c.clone();
            async move { relay_c.has_session(peer_a_id) }
        },
        Duration::from_secs(5),
    )
    .await;

    assert!(metric_value(&peer_a, MetricName::TrafficControlBytesTx, "net1") > a_control_tx_before);
    assert!(metric_value(&peer_a, MetricName::TrafficControlBytesRx, "net1") > a_control_rx_before);
    assert!(metric_value(&peer_c, MetricName::TrafficControlBytesTx, "net1") > c_control_tx_before);
    assert!(metric_value(&peer_c, MetricName::TrafficControlBytesRx, "net1") > c_control_rx_before);
}

#[tokio::test]
async fn relay_peer_map_responder_rejects_mismatched_pubkey() {
    // Create three peers: A -> B -> C
    let peer_a = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_b = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_c = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;

    connect_peer_manager(peer_a.clone(), peer_b.clone()).await;
    connect_peer_manager(peer_b.clone(), peer_c.clone()).await;

    let peer_a_id = peer_a.my_peer_id();
    let peer_c_id = peer_c.my_peer_id();

    // Wait for routes to propagate
    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            let peer_c = peer_c.clone();
            async move { wait_route_appear(peer_a.clone(), peer_c).await.is_ok() }
        },
        Duration::from_secs(10),
    )
    .await;

    // Wait for noise_static_pubkey to be available
    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            async move {
                peer_a
                    .get_peer_map()
                    .get_route_peer_info(peer_c_id)
                    .await
                    .map(|info| !info.noise_static_pubkey.is_empty())
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    // Get the original correct pubkey to verify it exists
    let original_info = peer_a
        .get_peer_map()
        .get_route_peer_info(peer_c_id)
        .await
        .expect("should have route info for peer_c");
    assert!(
        !original_info.noise_static_pubkey.is_empty(),
        "noise_static_pubkey should be present"
    );

    // Attempt handshake - this should succeed because pubkeys match
    let relay_a = peer_a.get_relay_peer_map();
    let result = relay_a
        .handshake_session(peer_c_id, NextHopPolicy::LeastHop, None)
        .await;

    // The handshake should succeed because the pubkeys match
    assert!(
        result.is_ok(),
        "handshake should succeed with matching pubkeys"
    );

    // Verify session was established on both sides
    wait_for_condition(
        || {
            let relay_a = relay_a.clone();
            async move { relay_a.has_session(peer_c_id) }
        },
        Duration::from_secs(5),
    )
    .await;

    let relay_c = peer_c.get_relay_peer_map();
    wait_for_condition(
        || {
            let relay_c = relay_c.clone();
            async move { relay_c.has_session(peer_a_id) }
        },
        Duration::from_secs(5),
    )
    .await;
}

#[tokio::test]
async fn relay_peer_map_remove_peer() {
    let (s, _r) = create_packet_recv_chan();
    let ctx = get_mock_global_ctx_with_network(Some(NetworkIdentity::new(
        "net1".to_string(),
        "sec1".to_string(),
    )));
    set_secure_mode_cfg(&ctx, true);
    let peer_map = Arc::new(PeerMap::new(s, ctx.clone(), 10));
    let store = Arc::new(PeerSessionStore::new());
    let relay_map = RelayPeerMap::new(peer_map, None, ctx.clone(), 10, store.clone());

    let peer_1: PeerId = 100;

    // Add session for peer_1
    let root_key = [1u8; 32];
    let session = Arc::new(PeerSession::new(
        peer_1,
        root_key,
        1,
        0,
        "aes-256-gcm".to_string(),
        "aes-256-gcm".to_string(),
        None,
    ));
    let key = SessionKey::new(ctx.get_network_name(), peer_1);
    store.insert_session(key.clone(), session);

    assert!(store.get(&key).is_some());

    // Remove the peer relay state
    relay_map.remove_peer(peer_1);

    // Session should still be in the store (lifecycle is independent of relay state)
    assert!(
        store.get(&key).is_some(),
        "session should persist after relay peer removal"
    );
}

/// Test bidirectional handshake race resolution.
/// When both peers simultaneously initiate handshake, the one with smaller peer_id
/// should become initiator, and the other should yield and become responder.
#[tokio::test]
async fn relay_peer_map_bidirectional_handshake_race() {
    // Create three peers: A -> B -> C
    let peer_a = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_b = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_c = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;

    connect_peer_manager(peer_a.clone(), peer_b.clone()).await;
    connect_peer_manager(peer_b.clone(), peer_c.clone()).await;

    let peer_a_id = peer_a.my_peer_id();
    let peer_c_id = peer_c.my_peer_id();

    // Wait for routes to propagate
    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            let peer_c = peer_c.clone();
            async move { wait_route_appear(peer_a.clone(), peer_c).await.is_ok() }
        },
        Duration::from_secs(10),
    )
    .await;

    // Wait for noise_static_pubkey to be available
    wait_for_condition(
        || {
            let peer_a = peer_a.clone();
            async move {
                peer_a
                    .get_peer_map()
                    .get_route_peer_info(peer_c_id)
                    .await
                    .map(|info| !info.noise_static_pubkey.is_empty())
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    wait_for_condition(
        || {
            let peer_c = peer_c.clone();
            async move {
                peer_c
                    .get_peer_map()
                    .get_route_peer_info(peer_a_id)
                    .await
                    .map(|info| !info.noise_static_pubkey.is_empty())
                    .unwrap_or(false)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    // Simulate bidirectional handshake race by having both sides initiate simultaneously
    let relay_a = peer_a.get_relay_peer_map();
    let relay_c = peer_c.get_relay_peer_map();

    // Both sides initiate handshake at the same time
    let handle_a = tokio::spawn({
        let relay_a = relay_a.clone();
        async move {
            relay_a
                .handshake_session(peer_c_id, NextHopPolicy::LeastHop, None)
                .await
        }
    });

    let handle_c = tokio::spawn({
        let relay_c = relay_c.clone();
        async move {
            relay_c
                .handshake_session(peer_a_id, NextHopPolicy::LeastHop, None)
                .await
        }
    });

    // Wait for both handshakes to complete
    let (result_a, result_c) = tokio::join!(handle_a, handle_c);

    // At least one should succeed (the initiator with smaller peer_id)
    // Both could succeed if race resolution worked correctly
    tracing::info!(
        ?peer_a_id,
        ?peer_c_id,
        ?result_a,
        ?result_c,
        "bidirectional handshake results"
    );

    // Wait for sessions to be established
    wait_for_condition(
        || {
            let relay_a = relay_a.clone();
            async move { relay_a.has_session(peer_c_id) }
        },
        Duration::from_secs(5),
    )
    .await;

    wait_for_condition(
        || {
            let relay_c = relay_c.clone();
            async move { relay_c.has_session(peer_a_id) }
        },
        Duration::from_secs(5),
    )
    .await;

    // Both sides should have sessions after race resolution
    assert!(
        relay_a.has_session(peer_c_id),
        "peer_a should have session with peer_c"
    );
    assert!(
        relay_c.has_session(peer_a_id),
        "peer_c should have session with peer_a"
    );
}

/// Helper: create a secure peer manager for a credential node.
/// Uses the given X25519 private key as the Noise static key, with no network_secret.
pub async fn create_mock_peer_manager_credential(
    network_name: String,
    private_key: &x25519_dalek::StaticSecret,
) -> Arc<PeerManager> {
    use crate::common::config::NetworkIdentity;
    use crate::proto::common::SecureModeConfig;
    use base64::Engine;
    use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;

    let (s, _r) = create_packet_recv_chan();
    let g = get_mock_global_ctx_with_network(Some(NetworkIdentity::new_credential(network_name)));

    let public = x25519_dalek::PublicKey::from(private_key);
    g.config.set_secure_mode(Some(SecureModeConfig {
        enabled: true,
        local_private_key: Some(BASE64_STANDARD.encode(private_key.as_bytes())),
        local_public_key: Some(BASE64_STANDARD.encode(public.as_bytes())),
    }));

    let peer_mgr = Arc::new(PeerManager::new(RouteAlgoType::Ospf, g, s));
    peer_mgr.run().await.unwrap();
    peer_mgr
}

/// Test: credential node joins a 2-admin network and routes appear.
/// Topology: Admin_A -- Credential_C, Admin_A -- Admin_B
/// Credential node connects to the admin that generated the credential.
#[tokio::test]
async fn credential_node_joins_network() {
    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_b = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    // Generate credential on admin_a
    let (_cred_id, cred_secret) = admin_a
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(
            vec!["guest".to_string()],
            false,
            vec![],
            std::time::Duration::from_secs(3600),
        );

    // Create credential node using the generated key
    let privkey_bytes: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let private = x25519_dalek::StaticSecret::from(privkey_bytes);
    let cred_c = create_mock_peer_manager_credential("net1".to_string(), &private).await;

    // Connect admins first
    connect_peer_manager(admin_a.clone(), admin_b.clone()).await;

    // Admin A and B should discover each other
    wait_route_appear(admin_a.clone(), admin_b.clone())
        .await
        .unwrap();

    // Now connect credential node to admin A (credential as client)
    connect_peer_manager(cred_c.clone(), admin_a.clone()).await;

    // Credential node C should be reachable from admin B (via A)
    let cred_c_id = cred_c.my_peer_id();
    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                admin_b
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == cred_c_id)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    // Credential node C should see admin B
    wait_for_condition(
        || {
            let cred_c = cred_c.clone();
            let admin_b_id = admin_b.my_peer_id();
            async move {
                cred_c
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == admin_b_id)
            }
        },
        Duration::from_secs(10),
    )
    .await;
}

/// Test: credential node is rejected when its pubkey is not in any admin's trusted list.
/// Topology: Admin_A -- Unknown_B (random key, not in trusted list)
#[tokio::test]
async fn unknown_credential_node_rejected() {
    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    // Create a credential node with a random key (NOT generated by admin)
    let random_private = x25519_dalek::StaticSecret::random_from_rng(rand::rngs::OsRng);
    let unknown_c = create_mock_peer_manager_credential("net1".to_string(), &random_private).await;

    // Try to connect: C -> A (unknown credential as client, admin as server)
    connect_peer_manager(unknown_c.clone(), admin_a.clone()).await;

    // The handshake should fail so the connection won't establish.
    // Wait a bit and verify no route appears.
    tokio::time::sleep(Duration::from_secs(3)).await;

    let routes = admin_a.list_routes().await;
    assert!(
        !routes.iter().any(|r| r.peer_id == unknown_c.my_peer_id()),
        "unknown credential node should NOT appear in admin's routes"
    );
}

/// Test: after revocation, the credential node disappears from routes.
/// Topology: Admin_A -- Credential_C, Admin_A -- Admin_B
/// After revocation on A, C should be removed from B's route table.
#[tokio::test]
async fn credential_revocation_removes_from_routes() {
    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_b = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    let (cred_id, cred_secret) = admin_a
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(vec![], false, vec![], std::time::Duration::from_secs(3600));

    let privkey_bytes: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let private = x25519_dalek::StaticSecret::from(privkey_bytes);
    let cred_c = create_mock_peer_manager_credential("net1".to_string(), &private).await;

    // Connect: A -- B, C -> A (credential node as client, admin as server)
    connect_peer_manager(admin_a.clone(), admin_b.clone()).await;
    connect_peer_manager(cred_c.clone(), admin_a.clone()).await;

    // Wait for credential node to appear in admin_b's routes
    let cred_c_id = cred_c.my_peer_id();
    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                admin_b
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == cred_c_id)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    // Now revoke the credential
    assert!(
        admin_a
            .get_global_ctx()
            .get_credential_manager()
            .revoke_credential(&cred_id)
    );
    // Issue event to trigger OSPF sync
    admin_a
        .get_global_ctx()
        .issue_event(crate::common::global_ctx::GlobalCtxEvent::CredentialChanged);

    // Wait for credential node to disappear from admin_b's routes
    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                !admin_b
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == cred_c_id)
            }
        },
        Duration::from_secs(15),
    )
    .await;
}

#[tokio::test]
async fn credential_expiry_disconnects_from_all_admins() {
    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_b = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    connect_peer_manager(admin_a.clone(), admin_b.clone()).await;
    wait_route_appear(admin_a.clone(), admin_b.clone())
        .await
        .unwrap();

    let (_cred_id, cred_secret) = admin_a
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(vec![], false, vec![], std::time::Duration::from_secs(2));

    admin_a
        .get_global_ctx()
        .issue_event(crate::common::global_ctx::GlobalCtxEvent::CredentialChanged);

    let privkey_bytes: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let private = x25519_dalek::StaticSecret::from(privkey_bytes);
    let cred_c = create_mock_peer_manager_credential("net1".to_string(), &private).await;
    let cred_c_id = cred_c.my_peer_id();

    connect_peer_manager(cred_c.clone(), admin_a.clone()).await;

    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                admin_b
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == cred_c_id)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    connect_peer_manager(cred_c.clone(), admin_b.clone()).await;

    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                admin_b
                    .get_peer_map()
                    .list_peer_conns(cred_c_id)
                    .await
                    .is_some_and(|conns| !conns.is_empty())
            }
        },
        Duration::from_secs(10),
    )
    .await;

    tokio::time::sleep(Duration::from_secs(3)).await;
    admin_a
        .get_global_ctx()
        .issue_event(crate::common::global_ctx::GlobalCtxEvent::CredentialChanged);

    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                !admin_b
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == cred_c_id)
            }
        },
        Duration::from_secs(20),
    )
    .await;

    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                admin_b
                    .get_peer_map()
                    .list_peer_conns(cred_c_id)
                    .await
                    .is_none_or(|conns| conns.is_empty())
            }
        },
        Duration::from_secs(20),
    )
    .await;
}

/// Test: admin node with credential — credential node gets group assignment.
/// Verify that the credential node's groups appear in the OSPF sync data.
#[tokio::test]
async fn credential_node_group_assignment() {
    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_b = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    let (_cred_id, cred_secret) = admin_a
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(
            vec!["guest".to_string(), "limited".to_string()],
            false,
            vec![],
            std::time::Duration::from_secs(3600),
        );

    let privkey_bytes: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let private = x25519_dalek::StaticSecret::from(privkey_bytes);
    let cred_c = create_mock_peer_manager_credential("net1".to_string(), &private).await;

    connect_peer_manager(admin_a.clone(), admin_b.clone()).await;
    connect_peer_manager(cred_c.clone(), admin_a.clone()).await;

    // Wait for credential node route to appear on admin_b (via OSPF through admin_a)
    let cred_c_id = cred_c.my_peer_id();
    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                admin_b
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == cred_c_id)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    // Verify the credential node's groups are assigned via OSPF on admin_b
    // (admin_b gets the groups from admin_a's TrustedCredentialPubkey via OSPF sync)
    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                let g = admin_b.get_route().get_peer_groups(cred_c_id);
                g.contains(&"guest".to_string()) && g.contains(&"limited".to_string())
            }
        },
        Duration::from_secs(10),
    )
    .await;
}

#[tokio::test]
async fn credential_node_connected_via_admin_b_trusts_admin_a_groups() {
    use crate::proto::acl::{Acl, AclV1, GroupIdentity, GroupInfo};

    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_b = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    let group_declares = vec![GroupIdentity {
        group_name: "platform-admin".to_string(),
        group_secret: "platform-admin-secret".to_string(),
    }];
    admin_a.get_global_ctx().config.set_acl(Some(Acl {
        acl_v1: Some(AclV1 {
            group: Some(GroupInfo {
                declares: group_declares.clone(),
                members: vec!["platform-admin".to_string()],
            }),
            ..Default::default()
        }),
    }));
    admin_b.get_global_ctx().config.set_acl(Some(Acl {
        acl_v1: Some(AclV1 {
            group: Some(GroupInfo {
                declares: group_declares,
                members: vec![],
            }),
            ..Default::default()
        }),
    }));

    connect_peer_manager(admin_a.clone(), admin_b.clone()).await;
    wait_route_appear(admin_a.clone(), admin_b.clone())
        .await
        .unwrap();

    let (_cred_id, cred_secret) = admin_a
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(vec![], false, vec![], std::time::Duration::from_secs(3600));
    admin_a
        .get_global_ctx()
        .issue_event(crate::common::global_ctx::GlobalCtxEvent::CredentialChanged);

    let privkey_bytes: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let private = x25519_dalek::StaticSecret::from(privkey_bytes);
    let credential_pubkey = x25519_dalek::PublicKey::from(&private).as_bytes().to_vec();

    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            let credential_pubkey = credential_pubkey.clone();
            async move {
                admin_b.get_global_ctx().is_pubkey_trusted_with_source(
                    &credential_pubkey,
                    "net1",
                    TrustedKeySource::OspfCredential,
                )
            }
        },
        Duration::from_secs(10),
    )
    .await;

    let cred_c = create_mock_peer_manager_credential("net1".to_string(), &private).await;
    connect_peer_manager(cred_c.clone(), admin_b.clone()).await;

    let admin_a_id = admin_a.my_peer_id();
    wait_for_condition(
        || {
            let cred_c = cred_c.clone();
            async move {
                cred_c
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == admin_a_id)
            }
        },
        Duration::from_secs(10),
    )
    .await;

    wait_for_condition(
        || {
            let cred_c = cred_c.clone();
            async move {
                cred_c
                    .get_route()
                    .get_peer_groups(admin_a_id)
                    .contains(&"platform-admin".to_string())
            }
        },
        Duration::from_secs(10),
    )
    .await;
}

/// Minimal test: two secure peers connect and discover each other's route.
#[tokio::test]
async fn two_secure_peers_route_appear() {
    let peer_a = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;
    let peer_b = create_mock_peer_manager_secure("net1".to_string(), "sec1".to_string()).await;

    connect_peer_manager(peer_a.clone(), peer_b.clone()).await;

    wait_route_appear(peer_a.clone(), peer_b.clone())
        .await
        .unwrap();
}

#[tokio::test]
async fn multi_admin_multi_credential_route_and_revocation_isolation() {
    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_b = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_d = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    connect_peer_manager(admin_a.clone(), admin_b.clone()).await;
    connect_peer_manager(admin_b.clone(), admin_d.clone()).await;
    connect_peer_manager(admin_a.clone(), admin_d.clone()).await;

    wait_route_appear(admin_a.clone(), admin_b.clone())
        .await
        .unwrap();
    wait_route_appear(admin_b.clone(), admin_d.clone())
        .await
        .unwrap();
    wait_route_appear(admin_a.clone(), admin_d.clone())
        .await
        .unwrap();

    let (cred1_id, cred1_secret) = admin_a
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(
            vec!["guest-a".to_string()],
            false,
            vec![],
            std::time::Duration::from_secs(3600),
        );
    let (_cred2_id, cred2_secret) = admin_b
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(
            vec!["guest-b".to_string()],
            false,
            vec![],
            std::time::Duration::from_secs(3600),
        );

    let cred1_private: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred1_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let cred2_private: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred2_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let cred_1 = create_mock_peer_manager_credential(
        "net1".to_string(),
        &x25519_dalek::StaticSecret::from(cred1_private),
    )
    .await;
    let cred_2 = create_mock_peer_manager_credential(
        "net1".to_string(),
        &x25519_dalek::StaticSecret::from(cred2_private),
    )
    .await;

    connect_peer_manager(cred_1.clone(), admin_a.clone()).await;
    connect_peer_manager(cred_2.clone(), admin_b.clone()).await;

    let cred_1_id = cred_1.my_peer_id();
    let cred_2_id = cred_2.my_peer_id();

    wait_for_condition(
        || {
            let admin_d = admin_d.clone();
            async move {
                let routes = admin_d.list_routes().await;
                routes.iter().any(|r| r.peer_id == cred_1_id)
                    && routes.iter().any(|r| r.peer_id == cred_2_id)
            }
        },
        Duration::from_secs(15),
    )
    .await;

    wait_for_condition(
        || {
            let admin_d = admin_d.clone();
            async move {
                let g1 = admin_d.get_route().get_peer_groups(cred_1_id);
                let g2 = admin_d.get_route().get_peer_groups(cred_2_id);
                g1.contains(&"guest-a".to_string()) && g2.contains(&"guest-b".to_string())
            }
        },
        Duration::from_secs(15),
    )
    .await;

    assert!(
        admin_a
            .get_global_ctx()
            .get_credential_manager()
            .revoke_credential(&cred1_id)
    );
    admin_a
        .get_global_ctx()
        .issue_event(crate::common::global_ctx::GlobalCtxEvent::CredentialChanged);

    wait_for_condition(
        || {
            let admin_d = admin_d.clone();
            async move {
                let routes = admin_d.list_routes().await;
                !routes.iter().any(|r| r.peer_id == cred_1_id)
                    && routes.iter().any(|r| r.peer_id == cred_2_id)
            }
        },
        Duration::from_secs(20),
    )
    .await;
}

#[tokio::test]
async fn unknown_credential_rejected_while_valid_credential_survives() {
    let admin_a = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;
    let admin_b = create_mock_peer_manager_secure("net1".to_string(), "secret".to_string()).await;

    connect_peer_manager(admin_a.clone(), admin_b.clone()).await;
    wait_route_appear(admin_a.clone(), admin_b.clone())
        .await
        .unwrap();

    let (_cred_id, cred_secret) = admin_a
        .get_global_ctx()
        .get_credential_manager()
        .generate_credential(
            vec!["stable".to_string()],
            false,
            vec![],
            std::time::Duration::from_secs(3600),
        );

    let valid_private: [u8; 32] = base64::engine::general_purpose::STANDARD
        .decode(&cred_secret)
        .unwrap()
        .try_into()
        .unwrap();
    let valid_cred = create_mock_peer_manager_credential(
        "net1".to_string(),
        &x25519_dalek::StaticSecret::from(valid_private),
    )
    .await;
    let unknown_private = x25519_dalek::StaticSecret::random_from_rng(rand::rngs::OsRng);
    let unknown_cred =
        create_mock_peer_manager_credential("net1".to_string(), &unknown_private).await;

    connect_peer_manager(valid_cred.clone(), admin_a.clone()).await;
    let (unknown_ring_client, unknown_ring_server) = create_ring_tunnel_pair();
    let unknown_connect_client = tokio::spawn({
        let unknown_cred = unknown_cred.clone();
        async move {
            unknown_cred
                .add_client_tunnel(unknown_ring_client, false)
                .await
        }
    });
    let unknown_connect_server = tokio::spawn({
        let admin_a = admin_a.clone();
        async move {
            admin_a
                .add_tunnel_as_server(unknown_ring_server, true)
                .await
        }
    });
    let (unknown_client_ret, unknown_server_ret) =
        tokio::join!(unknown_connect_client, unknown_connect_server);
    assert!(
        unknown_client_ret.unwrap().is_err() || unknown_server_ret.unwrap().is_err(),
        "unknown credential connection should fail on at least one side"
    );

    let valid_id = valid_cred.my_peer_id();
    let unknown_id = unknown_cred.my_peer_id();

    wait_for_condition(
        || {
            let admin_b = admin_b.clone();
            async move {
                admin_b
                    .list_routes()
                    .await
                    .iter()
                    .any(|r| r.peer_id == valid_id)
            }
        },
        Duration::from_secs(15),
    )
    .await;

    tokio::time::sleep(Duration::from_secs(5)).await;

    let routes = admin_b.list_routes().await;
    assert!(routes.iter().any(|r| r.peer_id == valid_id));
    assert!(!routes.iter().any(|r| r.peer_id == unknown_id));
}
