pub use crate::model::{Conversation, ConversationID, Message, MessageID, OutgoingMessage};

use async_trait::async_trait;
use bytes::Bytes;
use futures_util::Stream;

pub mod auth;
pub use crate::api::auth::{AuthenticationStore, InMemoryAuthenticationStore};

use crate::model::JwtToken;

pub mod http_client;
pub use http_client::HTTPAPIClient;

pub mod event_socket;
pub use event_socket::EventSocket;

use self::http_client::Credentials;
use std::fmt::Debug;

#[async_trait]
pub trait APIInterface {
    type Error: Debug;
    type ResponseStream: Stream<Item = Result<Bytes, Self::Error>>;

    // (GET) /version
    async fn get_version(&mut self) -> Result<String, Self::Error>;

    // (GET) /conversations
    async fn get_conversations(&mut self) -> Result<Vec<Conversation>, Self::Error>;

    // (GET) /messages
    async fn get_messages(
        &mut self,
        conversation_id: &ConversationID,
        limit: Option<u32>,
        before: Option<MessageID>,
        after: Option<MessageID>,
    ) -> Result<Vec<Message>, Self::Error>;

    // (POST) /sendMessage
    async fn send_message(
        &mut self,
        outgoing_message: &OutgoingMessage,
    ) -> Result<Message, Self::Error>;

    // (GET) /attachment
    async fn fetch_attachment_data(
        &mut self,
        guid: &str,
        preview: bool,
    ) -> Result<Self::ResponseStream, Self::Error>;

    // (POST) /uploadAttachment
    async fn upload_attachment<R>(
        &mut self,
        data: tokio::io::BufReader<R>,
        filename: &str,
        size: u64,
    ) -> Result<String, Self::Error>
    where
        R: tokio::io::AsyncRead + Unpin + Send + Sync + 'static;

    // (POST) /authenticate
    async fn authenticate(&mut self, credentials: Credentials) -> Result<JwtToken, Self::Error>;

    // (GET) /markConversation
    async fn mark_conversation_as_read(
        &mut self,
        conversation_id: &ConversationID,
    ) -> Result<(), Self::Error>;

    // (WS) /updates
    async fn open_event_socket(
        &mut self,
        update_seq: Option<u64>,
    ) -> Result<impl EventSocket, Self::Error>;
}
