use crate::io::{Error, ErrorType, Read, Write};
pub use super::{Headers, Method, Status};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Client<C>(C);
impl<C> Client<C>
where
    C: Connection,
{
    pub fn wrap(connection: C) -> Self {
        if connection.is_request_initiated() || connection.is_response_initiated() {
            panic!("connection is not in initial phase");
        }
        Self(connection)
    }
    pub fn connection(&mut self) -> &mut C {
        &mut self.0
    }
    pub fn release(self) -> C {
        self.0
    }
    pub fn get<'a>(&'a mut self, uri: &'a str) -> Result<Request<&'a mut C>, C::Error> {
        self.request(Method::Get, uri, &[])
    }
    pub fn post<'a>(
        &'a mut self,
        uri: &'a str,
        headers: &'a [(&'a str, &'a str)],
    ) -> Result<Request<&'a mut C>, C::Error> {
        self.request(Method::Post, uri, headers)
    }
    pub fn put<'a>(
        &'a mut self,
        uri: &'a str,
        headers: &'a [(&'a str, &'a str)],
    ) -> Result<Request<&'a mut C>, C::Error> {
        self.request(Method::Put, uri, headers)
    }
    pub fn delete<'a>(&'a mut self, uri: &'a str) -> Result<Request<&'a mut C>, C::Error> {
        self.request(Method::Delete, uri, &[])
    }
    pub fn request<'a>(
        &'a mut self,
        method: Method,
        uri: &'a str,
        headers: &'a [(&'a str, &'a str)],
    ) -> Result<Request<&'a mut C>, C::Error> {
        self.0.initiate_request(method, uri, headers)?;
        Ok(Request::wrap(&mut self.0))
    }
    pub fn raw_connection(&mut self) -> Result<&mut C::RawConnection, C::Error> {
        self.0.raw_connection()
    }
}
impl<C> ErrorType for Client<C>
where
    C: ErrorType,
{
    type Error = C::Error;
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Request<C>(C);
impl<C> Request<C>
where
    C: Connection,
{
    pub fn wrap(connection: C) -> Request<C> {
        if !connection.is_request_initiated() {
            panic!("connection is not in request phase");
        }
        Request(connection)
    }
    pub fn submit(mut self) -> Result<Response<C>, C::Error> {
        self.0.initiate_response()?;
        Ok(Response(self.0))
    }
    pub fn connection(&mut self) -> &mut C {
        &mut self.0
    }
    pub fn release(self) -> C {
        self.0
    }
    pub fn write(&mut self, buf: &[u8]) -> Result<usize, C::Error> {
        self.0.write(buf)
    }
    pub fn flush(&mut self) -> Result<(), C::Error> {
        self.0.flush()
    }
}
impl<C> ErrorType for Request<C>
where
    C: ErrorType,
{
    type Error = C::Error;
}
impl<C> Write for Request<C>
where
    C: Connection,
{
    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
        self.0.write(buf)
    }
    fn flush(&mut self) -> Result<(), Self::Error> {
        self.0.flush()
    }
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Response<C>(C);
impl<C> Response<C>
where
    C: Connection,
{
    pub fn wrap(connection: C) -> Response<C> {
        if !connection.is_response_initiated() {
            panic!("connection is not in response phase");
        }
        Response(connection)
    }
    pub fn split(&mut self) -> (&C::Headers, &mut C::Read) {
        self.0.split()
    }
    pub fn connection(&mut self) -> &mut C {
        &mut self.0
    }
    pub fn release(self) -> C {
        self.0
    }
    pub fn status(&self) -> u16 {
        self.0.status()
    }
    pub fn status_message(&self) -> Option<&'_ str> {
        self.0.status_message()
    }
    pub fn header(&self, name: &str) -> Option<&'_ str> {
        self.0.header(name)
    }
    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, C::Error> {
        self.0.read(buf)
    }
}
impl<C> Status for Response<C>
where
    C: Connection,
{
    fn status(&self) -> u16 {
        Response::status(self)
    }
    fn status_message(&self) -> Option<&'_ str> {
        Response::status_message(self)
    }
}
impl<C> Headers for Response<C>
where
    C: Connection,
{
    fn header(&self, name: &str) -> Option<&'_ str> {
        Response::header(self, name)
    }
}
impl<C> ErrorType for Response<C>
where
    C: ErrorType,
{
    type Error = C::Error;
}
impl<C> Read for Response<C>
where
    C: Connection,
{
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        Response::read(self, buf)
    }
}
pub trait Connection: Status + Headers + Read + Write {
    type Headers: Status + Headers;
    type Read: Read<Error = Self::Error>;
    type RawConnectionError: Error;
    type RawConnection: Read<Error = Self::RawConnectionError>
        + Write<Error = Self::RawConnectionError>;
    fn initiate_request<'a>(
        &'a mut self,
        method: Method,
        uri: &'a str,
        headers: &'a [(&'a str, &'a str)],
    ) -> Result<(), Self::Error>;
    fn is_request_initiated(&self) -> bool;
    fn initiate_response(&mut self) -> Result<(), Self::Error>;
    fn is_response_initiated(&self) -> bool;
    fn split(&mut self) -> (&Self::Headers, &mut Self::Read);
    fn raw_connection(&mut self) -> Result<&mut Self::RawConnection, Self::Error>;
}
impl<C> Connection for &mut C
where
    C: Connection,
{
    type Headers = C::Headers;
    type Read = C::Read;
    type RawConnectionError = C::RawConnectionError;
    type RawConnection = C::RawConnection;
    fn initiate_request<'a>(
        &'a mut self,
        method: Method,
        uri: &'a str,
        headers: &'a [(&'a str, &'a str)],
    ) -> Result<(), Self::Error> {
        (*self).initiate_request(method, uri, headers)
    }
    fn is_request_initiated(&self) -> bool {
        (**self).is_request_initiated()
    }
    fn initiate_response(&mut self) -> Result<(), Self::Error> {
        (*self).initiate_response()
    }
    fn is_response_initiated(&self) -> bool {
        (**self).is_response_initiated()
    }
    fn split(&mut self) -> (&Self::Headers, &mut Self::Read) {
        (*self).split()
    }
    fn raw_connection(&mut self) -> Result<&mut Self::RawConnection, Self::Error> {
        (*self).raw_connection()
    }
}
pub mod asynch {
    use crate::io::{asynch::Read, asynch::Write, Error, ErrorType};
    pub use crate::http::asynch::*;
    pub use crate::http::{Headers, Method, Status};
    #[derive(Debug)]
    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
    pub struct Client<C>(C);
    impl<C> Client<C>
    where
        C: Connection,
    {
        pub fn wrap(connection: C) -> Self {
            if connection.is_request_initiated() || connection.is_response_initiated() {
                panic!("connection is not in initial phase");
            }
            Self(connection)
        }
        pub fn connection(&mut self) -> &mut C {
            &mut self.0
        }
        pub fn release(self) -> C {
            self.0
        }
        pub async fn get<'a>(&'a mut self, uri: &'a str) -> Result<Request<&'a mut C>, C::Error> {
            self.request(Method::Get, uri, &[]).await
        }
        pub async fn post<'a>(
            &'a mut self,
            uri: &'a str,
            headers: &'a [(&'a str, &'a str)],
        ) -> Result<Request<&'a mut C>, C::Error> {
            self.request(Method::Post, uri, headers).await
        }
        pub async fn put<'a>(
            &'a mut self,
            uri: &'a str,
            headers: &'a [(&'a str, &'a str)],
        ) -> Result<Request<&'a mut C>, C::Error> {
            self.request(Method::Put, uri, headers).await
        }
        pub async fn delete<'a>(
            &'a mut self,
            uri: &'a str,
        ) -> Result<Request<&'a mut C>, C::Error> {
            self.request(Method::Delete, uri, &[]).await
        }
        pub async fn request<'a>(
            &'a mut self,
            method: Method,
            uri: &'a str,
            headers: &'a [(&'a str, &'a str)],
        ) -> Result<Request<&'a mut C>, C::Error> {
            self.0.initiate_request(method, uri, headers).await?;
            Ok(Request::wrap(&mut self.0))
        }
        pub fn raw_connection(&mut self) -> Result<&mut C::RawConnection, C::Error> {
            self.0.raw_connection()
        }
    }
    impl<C> ErrorType for Client<C>
    where
        C: ErrorType,
    {
        type Error = C::Error;
    }
    #[derive(Debug)]
    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
    pub struct Request<C>(C);
    impl<C> Request<C>
    where
        C: Connection,
    {
        pub fn wrap(connection: C) -> Request<C> {
            if !connection.is_request_initiated() {
                panic!("connection is not in request phase");
            }
            Request(connection)
        }
        pub async fn submit(mut self) -> Result<Response<C>, C::Error> {
            self.0.initiate_response().await?;
            Ok(Response(self.0))
        }
        pub fn connection(&mut self) -> &mut C {
            &mut self.0
        }
        pub fn release(self) -> C {
            self.0
        }
        pub async fn write(&mut self, buf: &[u8]) -> Result<usize, C::Error> {
            self.0.write(buf).await
        }
        pub async fn flush(&mut self) -> Result<(), C::Error> {
            self.0.flush().await
        }
    }
    impl<C> ErrorType for Request<C>
    where
        C: ErrorType,
    {
        type Error = C::Error;
    }
    impl<C> Write for Request<C>
    where
        C: Connection,
    {
        async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
            Request::write(self, buf).await
        }
        async fn flush(&mut self) -> Result<(), Self::Error> {
            Request::flush(self).await
        }
    }
    #[derive(Debug)]
    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
    pub struct Response<C>(C);
    impl<C> Response<C>
    where
        C: Connection,
    {
        pub fn wrap(connection: C) -> Response<C> {
            if !connection.is_response_initiated() {
                panic!("connection is not in response phase");
            }
            Response(connection)
        }
        pub fn split(&mut self) -> (&C::Headers, &mut C::Read) {
            self.0.split()
        }
        pub fn connection(&mut self) -> &mut C {
            &mut self.0
        }
        pub fn release(self) -> C {
            self.0
        }
        pub fn status(&self) -> u16 {
            self.0.status()
        }
        pub fn status_message(&self) -> Option<&'_ str> {
            self.0.status_message()
        }
        pub fn header(&self, name: &str) -> Option<&'_ str> {
            self.0.header(name)
        }
        pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, C::Error> {
            self.0.read(buf).await
        }
    }
    impl<C> Status for Response<C>
    where
        C: Connection,
    {
        fn status(&self) -> u16 {
            Response::status(self)
        }
        fn status_message(&self) -> Option<&'_ str> {
            Response::status_message(self)
        }
    }
    impl<C> Headers for Response<C>
    where
        C: Connection,
    {
        fn header(&self, name: &str) -> Option<&'_ str> {
            Response::header(self, name)
        }
    }
    impl<C> ErrorType for Response<C>
    where
        C: ErrorType,
    {
        type Error = C::Error;
    }
    impl<C> Read for Response<C>
    where
        C: Connection,
    {
        async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
            Response::read(self, buf).await
        }
    }
    pub trait Connection: Status + Headers + Read + Write {
        type Headers: Status + Headers;
        type Read: Read<Error = Self::Error>;
        type RawConnectionError: Error;
        type RawConnection: Read<Error = Self::RawConnectionError>
            + Write<Error = Self::RawConnectionError>;
        async fn initiate_request(
            &mut self,
            method: Method,
            uri: &str,
            headers: &[(&str, &str)],
        ) -> Result<(), Self::Error>;
        fn is_request_initiated(&self) -> bool;
        async fn initiate_response(&mut self) -> Result<(), Self::Error>;
        fn is_response_initiated(&self) -> bool;
        fn split(&mut self) -> (&Self::Headers, &mut Self::Read);
        fn raw_connection(&mut self) -> Result<&mut Self::RawConnection, Self::Error>;
    }
    impl<C> Connection for &mut C
    where
        C: Connection,
    {
        type Headers = C::Headers;
        type Read = C::Read;
        type RawConnectionError = C::RawConnectionError;
        type RawConnection = C::RawConnection;
        async fn initiate_request(
            &mut self,
            method: Method,
            uri: &str,
            headers: &[(&str, &str)],
        ) -> Result<(), Self::Error> {
            (*self).initiate_request(method, uri, headers).await
        }
        fn is_request_initiated(&self) -> bool {
            (**self).is_request_initiated()
        }
        async fn initiate_response(&mut self) -> Result<(), Self::Error> {
            (*self).initiate_response().await
        }
        fn is_response_initiated(&self) -> bool {
            (**self).is_response_initiated()
        }
        fn split(&mut self) -> (&Self::Headers, &mut Self::Read) {
            (*self).split()
        }
        fn raw_connection(&mut self) -> Result<&mut Self::RawConnection, Self::Error> {
            (*self).raw_connection()
        }
    }
}