use std::fmt::Display;
use futures::channel::mpsc;
use parity_scale_codec::{Decode, Encode};
use crate::{
    crypto::{AuthorityPen, AuthorityVerifier, Signature},
    network::{
        data::{
            component::{Sender, SimpleNetwork},
            SendError,
        },
        AddressingInformation, Data,
    },
    NodeIndex, Recipient, SessionId,
};
mod compatibility;
mod connections;
mod data;
mod discovery;
mod handler;
mod manager;
mod service;
pub use compatibility::{DiscoveryMessage, VersionedAuthentication};
use connections::Connections;
#[cfg(test)]
pub use data::DataInSession;
pub use discovery::Discovery;
#[cfg(test)]
pub use handler::tests::authentication;
pub use handler::{Handler as SessionHandler, HandlerError as SessionHandlerError};
pub use service::{Config as ConnectionManagerConfig, Service as ConnectionManager};
#[allow(unused_imports)]
pub use service::ManagerError;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encode, Decode)]
pub struct AuthData<A: AddressingInformation> {
    address: A,
    node_id: NodeIndex,
    session_id: SessionId,
}
impl<A: AddressingInformation> AuthData<A> {
    pub fn session(&self) -> SessionId {
        self.session_id
    }
    pub fn creator(&self) -> NodeIndex {
        self.node_id
    }
    pub fn address(&self) -> A {
        self.address.clone()
    }
}
#[derive(Clone, Decode, Encode, Debug, Eq, PartialEq, Hash)]
pub struct Authentication<A: AddressingInformation>(AuthData<A>, Signature);
#[derive(Clone)]
pub struct SessionSender<D: Data> {
    session_id: SessionId,
    messages_for_network: mpsc::UnboundedSender<(D, SessionId, Recipient)>,
}
impl<D: Data> Sender<D> for SessionSender<D> {
    fn send(&self, data: D, recipient: Recipient) -> Result<(), SendError> {
        self.messages_for_network
            .unbounded_send((data, self.session_id, recipient))
            .map_err(|_| SendError::SendFailed)
    }
}
type Network<D> = SimpleNetwork<D, mpsc::UnboundedReceiver<D>, SessionSender<D>>;
#[async_trait::async_trait]
pub trait SessionManager<D: Data>: Send + Sync + 'static {
    type Error: Display;
    fn start_nonvalidator_session(
        &self,
        session_id: SessionId,
        verifier: AuthorityVerifier,
    ) -> Result<(), Self::Error>;
    async fn start_validator_session(
        &self,
        session_id: SessionId,
        verifier: AuthorityVerifier,
        node_id: NodeIndex,
        pen: AuthorityPen,
    ) -> Result<Network<D>, Self::Error>;
    fn early_start_validator_session(
        &self,
        session_id: SessionId,
        verifier: AuthorityVerifier,
        node_id: NodeIndex,
        pen: AuthorityPen,
    ) -> Result<(), Self::Error>;
    fn stop_session(&self, session_id: SessionId) -> Result<(), Self::Error>;
}