use std::any::{Any, TypeId};
use std::sync::Arc;
use async_std::sync::Mutex;
use serde::{Deserialize, Serialize};
use ng_repo::errors::*;
use ng_repo::log::*;
use ng_repo::types::UserId;
use crate::actors::noise::Noise;
use crate::connection::NoiseFSM;
use crate::types::{
    AdminRequest, ClientInfo, CoreBrokerConnect, CoreBrokerConnectResponse, CoreMessage,
    CoreMessageV0, CoreResponse, CoreResponseContentV0, CoreResponseV0, ExtResponse,
};
use crate::{actor::*, types::ProtocolMessage};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum StartProtocol {
    Client(ClientHello),
    Ext(ExtHello),
    Core(CoreHello),
    Admin(AdminRequest),
    App(AppHello),
    AppResponse(AppHelloResponse),
}
impl StartProtocol {
    pub fn type_id(&self) -> TypeId {
        match self {
            StartProtocol::Client(a) => a.type_id(),
            StartProtocol::Core(a) => a.type_id(),
            StartProtocol::Ext(a) => a.type_id(),
            StartProtocol::Admin(a) => a.type_id(),
            StartProtocol::App(a) => a.type_id(),
            StartProtocol::AppResponse(a) => a.type_id(),
        }
    }
    pub fn get_actor(&self) -> Box<dyn EActor> {
        match self {
            StartProtocol::Client(a) => a.get_actor(),
            StartProtocol::Core(a) => a.get_actor(),
            StartProtocol::Ext(a) => a.get_actor(),
            StartProtocol::Admin(a) => a.get_actor(),
            StartProtocol::App(a) => a.get_actor(),
            StartProtocol::AppResponse(_) => panic!("AppResponse is not a request"),
        }
    }
}
impl From<StartProtocol> for ProtocolMessage {
    fn from(msg: StartProtocol) -> ProtocolMessage {
        ProtocolMessage::Start(msg)
    }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CoreHello {
    pub noise: Noise,
    #[serde(with = "serde_bytes")]
    pub payload: Vec<u8>,
}
impl CoreHello {
    pub fn get_actor(&self) -> Box<dyn EActor> {
        Actor::<CoreBrokerConnect, CoreBrokerConnectResponse>::new_responder(0)
    }
}
impl TryFrom<ProtocolMessage> for CoreBrokerConnectResponse {
    type Error = ProtocolError;
    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
        if let ProtocolMessage::CoreMessage(CoreMessage::V0(CoreMessageV0::Response(
            CoreResponse::V0(CoreResponseV0 {
                content: CoreResponseContentV0::BrokerConnectResponse(a),
                ..
            }),
        ))) = msg
        {
            Ok(a)
        } else {
            log_debug!("INVALID {:?}", msg);
            Err(ProtocolError::InvalidValue)
        }
    }
}
impl From<CoreHello> for ProtocolMessage {
    fn from(msg: CoreHello) -> ProtocolMessage {
        ProtocolMessage::Start(StartProtocol::Core(msg))
    }
}
impl From<CoreBrokerConnect> for ProtocolMessage {
    fn from(_msg: CoreBrokerConnect) -> ProtocolMessage {
        unimplemented!();
    }
}
impl Actor<'_, CoreBrokerConnect, CoreBrokerConnectResponse> {}
#[async_trait::async_trait]
impl EActor for Actor<'_, CoreBrokerConnect, CoreBrokerConnectResponse> {
    async fn respond(
        &mut self,
        _msg: ProtocolMessage,
        _fsm: Arc<Mutex<NoiseFSM>>,
    ) -> Result<(), ProtocolError> {
        Ok(())
    }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ExtHello {
    pub noise: Noise,
    #[serde(with = "serde_bytes")]
    pub payload: Vec<u8>,
}
impl ExtHello {
    pub fn get_actor(&self) -> Box<dyn EActor> {
        Actor::<ExtHello, ExtResponse>::new_responder(0)
    }
}
impl From<ExtHello> for ProtocolMessage {
    fn from(msg: ExtHello) -> ProtocolMessage {
        ProtocolMessage::Start(StartProtocol::Ext(msg))
    }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ClientHello {
    Noise3(Noise),
    Local,
}
impl ClientHello {
    pub fn type_id(&self) -> TypeId {
        match self {
            ClientHello::Noise3(a) => a.type_id(),
            ClientHello::Local => TypeId::of::<ClientHello>(),
        }
    }
    pub fn get_actor(&self) -> Box<dyn EActor> {
        Actor::<ClientHello, ServerHello>::new_responder(0)
    }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ServerHelloV0 {
    #[serde(with = "serde_bytes")]
    pub nonce: Vec<u8>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ServerHello {
    V0(ServerHelloV0),
}
impl ServerHello {
    pub fn nonce(&self) -> &Vec<u8> {
        match self {
            ServerHello::V0(o) => &o.nonce,
        }
    }
}
impl From<ClientHello> for ProtocolMessage {
    fn from(msg: ClientHello) -> ProtocolMessage {
        ProtocolMessage::Start(StartProtocol::Client(msg))
    }
}
impl TryFrom<ProtocolMessage> for ClientHello {
    type Error = ProtocolError;
    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
        if let ProtocolMessage::Start(StartProtocol::Client(a)) = msg {
            Ok(a)
        } else {
            Err(ProtocolError::InvalidValue)
        }
    }
}
impl TryFrom<ProtocolMessage> for ServerHello {
    type Error = ProtocolError;
    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
        if let ProtocolMessage::ServerHello(server_hello) = msg {
            Ok(server_hello)
        } else {
            Err(ProtocolError::InvalidValue)
        }
    }
}
impl From<ServerHello> for ProtocolMessage {
    fn from(msg: ServerHello) -> ProtocolMessage {
        ProtocolMessage::ServerHello(msg)
    }
}
impl Actor<'_, ClientHello, ServerHello> {}
#[async_trait::async_trait]
impl EActor for Actor<'_, ClientHello, ServerHello> {
    async fn respond(
        &mut self,
        msg: ProtocolMessage,
        fsm: Arc<Mutex<NoiseFSM>>,
    ) -> Result<(), ProtocolError> {
        let _req = ClientHello::try_from(msg)?;
        let res = ServerHello::V0(ServerHelloV0 { nonce: vec![] });
        fsm.lock().await.send(res.into()).await?;
        Ok(())
    }
}
impl Actor<'_, ExtHello, ExtResponse> {}
#[async_trait::async_trait]
impl EActor for Actor<'_, ExtHello, ExtResponse> {
    async fn respond(
        &mut self,
        _msg: ProtocolMessage,
        _fsm: Arc<Mutex<NoiseFSM>>,
    ) -> Result<(), ProtocolError> {
        Ok(())
    }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppHello {
    pub noise: Noise,
    pub user: Option<UserId>, pub info: ClientInfo,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppHelloResponse {
    pub result: u16,
}
impl AppHello {
    pub fn get_actor(&self) -> Box<dyn EActor> {
        Actor::<AppHello, AppHelloResponse>::new_responder(0)
    }
}
impl From<AppHello> for ProtocolMessage {
    fn from(msg: AppHello) -> ProtocolMessage {
        ProtocolMessage::Start(StartProtocol::App(msg))
    }
}
impl From<AppHelloResponse> for ProtocolMessage {
    fn from(msg: AppHelloResponse) -> ProtocolMessage {
        ProtocolMessage::Start(StartProtocol::AppResponse(msg))
    }
}
impl TryFrom<ProtocolMessage> for AppHelloResponse {
    type Error = ProtocolError;
    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
        if let ProtocolMessage::Start(StartProtocol::AppResponse(res)) = msg {
            Ok(res)
        } else {
            Err(ProtocolError::InvalidValue)
        }
    }
}
impl Actor<'_, AppHello, AppHelloResponse> {}
#[async_trait::async_trait]
impl EActor for Actor<'_, AppHello, AppHelloResponse> {
    async fn respond(
        &mut self,
        _msg: ProtocolMessage,
        _fsm: Arc<Mutex<NoiseFSM>>,
    ) -> Result<(), ProtocolError> {
        Ok(())
    }
}