use futures::Future;
use nostr_rs_client::{Error as ClientError, Relayers};
use nostr_rs_storage::RocksDb;
use nostr_rs_types::{client::Subscribe, Request, Response};
use std::pin::Pin;
use tokio::sync::mpsc;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("Nostr: {0}")]
    Addr(#[from] nostr_rs_types::types::addr::Error),

    #[error("client: {0}")]
    Client(#[from] ClientError),
}

fn on_connection(
    sent_messages: Vec<Request>,
    socket: mpsc::Sender<Request>,
) -> Pin<Box<dyn Future<Output = ()> + Send>> {
    println!("Reconnecting with {:?}", sent_messages);
    Box::pin(async move {
        for m in sent_messages {
            let _ = socket.send(m).await;
        }
    })
}

#[tokio::main]
async fn main() {
    env_logger::init();
    let (mut clients, mut receiver) = Relayers::new();
    clients.send(Subscribe::default().into()).await;

    let _ = clients
        .connect_to("wss://relay.damus.io/", u16::MAX, Some(on_connection))
        .await;
    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 db = RocksDb::new("./db").expect("db");

    tokio::spawn(async move {
        loop {
            clients.get_connections().iter().for_each(|relayer| {
                if relayer.is_connected() {
                    log::warn!("Connected to {}", relayer.url);
                }
            });
            tokio::time::sleep(std::time::Duration::from_secs(10)).await;
        }
    });

    loop {
        if let Some((msg, _relayed_by)) = receiver.recv().await {
            match msg {
                Response::Event(x) => {
                    let event = x.event;
                    db.store(&event).expect("valid");
                }
                Response::EndOfStoredEvents(_) => {}
                msg => {
                    panic!("{:?}", msg);
                }
            }
        }
    }
}
