//! Simulated mesh leg: **A (LoRa)** → **B (LoRa + TCP relay)** → **C (TCP)** → zurück über B → **A**.
//!
//! Uses [`quicprochat_p2p::transport_lora::LoRaMockMedium`] — keine Hardware.
//!
//! ```text
//!   Node A                Node B                      Node C
//!  LoRa addr 0x01   LoRa 0x02 + TCP listen      TCP (WiFi / LAN)
//!       │                 │                           │
//!       └──── LoRa ───────┘                           │
//!                         └──────── TCP ──────────────┘
//! ```
//!
//! Run: `cargo run -p quicprochat-p2p --example mesh_lora_relay_demo`

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

use quicprochat_p2p::transport::{MeshTransport, TransportAddr};
use quicprochat_p2p::transport_lora::{DutyCycleTracker, LoRaConfig, LoRaMockMedium};
use quicprochat_p2p::transport_tcp::TcpTransport;

const ADDR_A: [u8; 4] = [0x01, 0, 0, 0];
const ADDR_B: [u8; 4] = [0x02, 0, 0, 0];

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let medium = LoRaMockMedium::new();
    let duty = Arc::new(DutyCycleTracker::new(3_600_000));

    let lora_a = medium
        .connect(ADDR_A, LoRaConfig::default(), Arc::clone(&duty))
        .await?;
    let lora_b = medium
        .connect(ADDR_B, LoRaConfig::default(), Arc::clone(&duty))
        .await?;

    let tcp_b = TcpTransport::bind("127.0.0.1:0").await?;
    let tcp_c = TcpTransport::bind("127.0.0.1:0").await?;

    let c_listen = tcp_c.local_addr();
    let b_listen = tcp_b.local_addr();
    let c_addr = TransportAddr::Socket(c_listen);
    let b_addr = TransportAddr::Socket(b_listen);

    println!(
        "LoRa mock mesh demo: B relays LoRa <-> TCP (B TCP {}, C TCP {})",
        b_listen, c_listen
    );

    let relay = tokio::spawn(async move {
        for _ in 0..2 {
            tokio::select! {
                p = lora_b.recv() => {
                    let p = p.expect("B LoRa recv");
                    println!("B: LoRa from {} -> TCP ({} bytes)", p.from, p.data.len());
                    tcp_b.send(&c_addr, &p.data).await.expect("B TCP send to C");
                }
                p = tcp_b.recv() => {
                    let p = p.expect("B TCP recv");
                    println!("B: TCP -> LoRa A ({} bytes)", p.data.len());
                    lora_b
                        .send(&TransportAddr::LoRa(ADDR_A), &p.data)
                        .await
                        .expect("B LoRa send to A");
                }
            }
        }
    });

    let c_task = tokio::spawn(async move {
        let pkt = tcp_c.recv().await.expect("C TCP recv");
        println!("C: got {} bytes from B relay", pkt.data.len());
        assert_eq!(pkt.data, b"hello via mesh");
        tcp_c
            .send(&b_addr, b"ack from C")
            .await
            .expect("C TCP send");
    });

    tokio::time::sleep(Duration::from_millis(50)).await;

    lora_a
        .send(&TransportAddr::LoRa(ADDR_B), b"hello via mesh")
        .await?;

    let reply = lora_a.recv().await?;
    println!("A: LoRa reply {} bytes", reply.data.len());
    assert_eq!(reply.data, b"ack from C");

    c_task.await.expect("node C task panicked");
    relay.await.expect("relay task panicked");

    lora_a.close().await.ok();
    println!("Done: LoRa + TCP relay path OK.");
    Ok(())
}
