use futures::Future;
use nostr_rs_storage::RocksDb;
use nostr_rs_types::{Request, Response};
use std::{pin::Pin, sync::Arc};
use tokio::{
    net::TcpListener,
    sync::mpsc,
    time::{sleep, Duration},
};

fn on_connection(
    _sent_messages: Vec<Request>,
    _socket: mpsc::Sender<Request>,
) -> Pin<Box<dyn Future<Output = ()> + Send>> {
    Box::pin(async move {})
}

#[tokio::main]
async fn main() {
    env_logger::init();
    let db = RocksDb::new("./relayer-db").expect("db");
    let (relayer, mut server_receiver) = nostr_rs_relayer::Relayer::new(db);
    let (mut clients, mut client_receiver) = nostr_rs_client::Relayers::new();
    let _ = clients
        .connect_to("wss://relay.damus.io/", u16::MAX, Some(on_connection))
        .await
        .expect("valid connection");
    let _ = clients
        .connect_to("wss://brb.io", u16::MAX, Some(on_connection))
        .await;
    let _ = clients
        .connect_to("wss://nos.lol", u16::MAX, Some(on_connection))
        .await;
    let _ = clients
        .connect_to("wss://relay.current.fyi", u16::MAX, Some(on_connection))
        .await;
    let _ = clients
        .connect_to("wss://eden.nostr.land", u16::MAX, Some(on_connection))
        .await;
    let _ = clients
        .connect_to("wss://relay.snort.social", u16::MAX, Some(on_connection))
        .await;

    let addr = "127.0.0.1:3000";
    let listener = TcpListener::bind(&addr).await.unwrap();

    let relayer_for_recv = relayer.clone();
    let relayer_for_client = relayer.clone();
    let relayer_for_republisher = relayer.clone();

    let clients = Arc::new(clients);
    let clients_for_republisher = clients.clone();

    tokio::spawn(async move {
        loop {
            if let Ok(events) = relayer_for_republisher.get_db().get_local_events() {
                println!("Rebroadcast: {:?} ", events);
                for event in events.into_iter() {
                    println!("Rebroadcasting: {}", serde_json::to_string(&event).unwrap());
                    let _ = clients_for_republisher.send(event.into()).await;
                }
            }
            sleep(Duration::from_secs(360)).await;
        }
    });

    tokio::spawn(async move {
        loop {
            let (event, _) = client_receiver.recv().await.unwrap();
            println!(
                "received event: {}",
                serde_json::to_string(&event).expect("valid json")
            );
            match &event {
                Response::Event(event) => {
                    let _ = relayer_for_client.store_and_broadcast(&event.event);
                }
                _msg => {
                    //println!("Sending message: {:?}", msg);
                    //let _ = relayer_for_client.send(msg).await;
                }
            }
        }
    });

    tokio::spawn(async move {
        loop {
            let x = relayer_for_recv.recv(&mut server_receiver).await.unwrap();
            if let Some(x) = x {
                println!(
                    "received event: {}",
                    serde_json::to_string(&x).expect("valid json")
                );
                clients.send(x).await;
            }
        }
    });

    loop {
        let (stream, _) = listener.accept().await.unwrap();
        let addr = stream.peer_addr().unwrap();

        println!("Client {} connected", addr);

        let _ = relayer.add_connection(stream).await;
    }
}
