use iroh::{Endpoint, endpoint::presets};
use iroh_gossip::net::Gossip;
use peerspeak::network::{PeerState, RoomState, gossip::IrohGossipState};
use tokio::time::{self, Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Starting network loopback test...");

    // 1. Node A (Host) Setup
    let lookup_a = iroh::address_lookup::memory::MemoryLookup::new();
    let secret_a = iroh::SecretKey::generate();
    let endpoint_a = Endpoint::builder(presets::N0)
        .secret_key(secret_a.clone())
        .address_lookup(lookup_a.clone())
        .bind()
        .await?;

    endpoint_a.online().await;
    println!("Node A online. ID: {}", endpoint_a.id());

    let gossip_a = Gossip::builder().spawn(endpoint_a.clone());
    let _router_a = iroh::protocol::Router::builder(endpoint_a.clone())
        .accept(iroh_gossip::net::GOSSIP_ALPN, gossip_a.clone())
        .spawn();

    let room_a = IrohGossipState::new(
        endpoint_a.clone(),
        gossip_a.clone(),
        lookup_a.clone(),
        secret_a,
    );

    // 2. Node B (Client) Setup
    let lookup_b = iroh::address_lookup::memory::MemoryLookup::new();
    let secret_b = iroh::SecretKey::generate();
    let endpoint_b = Endpoint::builder(presets::N0)
        .secret_key(secret_b.clone())
        .address_lookup(lookup_b.clone())
        .bind()
        .await?;

    endpoint_b.online().await;
    println!("Node B online. ID: {}", endpoint_b.id());

    let gossip_b = Gossip::builder().spawn(endpoint_b.clone());
    let _router_b = iroh::protocol::Router::builder(endpoint_b.clone())
        .accept(iroh_gossip::net::GOSSIP_ALPN, gossip_b.clone())
        .spawn();

    let room_b = IrohGossipState::new(
        endpoint_b.clone(),
        gossip_b.clone(),
        lookup_b.clone(),
        secret_b,
    );

    // 3. Create room on Node A
    let topic_id = rand::random();
    let ticket = peerspeak::network::PeerSpeakTicket {
        host_addr: endpoint_a.addr(),
        topic_id,
        name: String::new(),
    };
    let ticket_str = ticket.to_string();
    println!("Ticket generated: {}", ticket_str);

    let state_a = PeerState {
        name: "Alice".to_string(),
        is_muted: false,
        addr: endpoint_a.addr(),
        sharing: None,
        avatar: Default::default(),
        game: None,
        music: None,
    };
    room_a.join(&ticket_str, state_a, vec![]).await?;
    println!("Node A joined topic.");

    // Subscribe to events on Node A
    let mut rx_a = room_a.subscribe_events().await?;
    tokio::spawn(async move {
        while let Some(event) = rx_a.recv().await {
            println!("Node A Event: {:?}", event);
        }
    });

    // 4. Join room on Node B
    let state_b = PeerState {
        name: "Bob".to_string(),
        is_muted: false,
        addr: endpoint_b.addr(),
        sharing: None,
        avatar: Default::default(),
        game: None,
        music: None,
    };
    room_b.join(&ticket_str, state_b, vec![]).await?;
    println!("Node B joined topic.");

    // Subscribe to events on Node B
    let mut rx_b = room_b.subscribe_events().await?;
    tokio::spawn(async move {
        while let Some(event) = rx_b.recv().await {
            println!("Node B Event: {:?}", event);
        }
    });

    // Wait and check connection
    println!("Waiting 10 seconds for Gossip sync...");
    time::sleep(Duration::from_secs(10)).await;

    println!("Alice's peers: {:?}", room_a.active_peers());
    println!("Bob's peers: {:?}", room_b.active_peers());

    println!("Test finished.");
    Ok(())
}
