use cfg_if::cfg_if;
use s2n_quic_core::crypto;
pub trait Provider {
    type Server: 'static + crypto::tls::Endpoint;
    type Client: 'static + crypto::tls::Endpoint;
    type Error: 'static + core::fmt::Display + Send + Sync;
    fn start_server(self) -> Result<Self::Server, Self::Error>;
    fn start_client(self) -> Result<Self::Client, Self::Error>;
}
impl_provider_utils!();
cfg_if! {
    if #[cfg(feature = "provider-tls-default")] {
        pub mod default {
            pub use super::default_tls::*;
        }
    } else if #[cfg(feature = "provider-tls-s2n")] {
        pub use s2n_tls as default;
    } else if #[cfg(feature = "provider-tls-rustls")] {
        pub use rustls as default;
    } else {
        pub mod default {
            pub use super::default_tls::*;
        }
    }
}
#[derive(Debug, Default)]
pub struct Default;
impl Provider for Default {
    type Server = default::Server;
    type Client = default::Client;
    type Error = core::convert::Infallible;
    fn start_server(self) -> Result<Self::Server, Self::Error> {
        Ok(Self::Server::default())
    }
    fn start_client(self) -> Result<Self::Client, Self::Error> {
        Ok(Self::Client::default())
    }
}
impl Provider for (&std::path::Path, &std::path::Path) {
    type Server = <Default as Provider>::Server;
    type Client = <Default as Provider>::Client;
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn start_server(self) -> Result<Self::Server, Self::Error> {
        let server = default::Server::builder()
            .with_certificate(self.0, self.1)?
            .build()?;
        Ok(server)
    }
    fn start_client(self) -> Result<Self::Client, Self::Error> {
        let client = default::Client::builder()
            .with_certificate(self.0)?
            .build()?;
        Ok(client)
    }
}
impl Provider for &std::path::Path {
    type Server = <Default as Provider>::Server;
    type Client = <Default as Provider>::Client;
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn start_server(self) -> Result<Self::Server, Self::Error> {
        let empty_cert: &[u8] = &[];
        let server = default::Server::builder()
            .with_certificate(empty_cert, self)?
            .build()?;
        Ok(server)
    }
    fn start_client(self) -> Result<Self::Client, Self::Error> {
        let client = default::Client::builder().with_certificate(self)?.build()?;
        Ok(client)
    }
}
impl Provider for (&[u8], &[u8]) {
    type Server = <Default as Provider>::Server;
    type Client = <Default as Provider>::Client;
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn start_server(self) -> Result<Self::Server, Self::Error> {
        let server = default::Server::builder()
            .with_certificate(self.0, self.1)?
            .build()?;
        Ok(server)
    }
    fn start_client(self) -> Result<Self::Client, Self::Error> {
        let client = default::Client::builder()
            .with_certificate(self.0)?
            .build()?;
        Ok(client)
    }
}
impl Provider for &[u8] {
    type Server = <Default as Provider>::Server;
    type Client = <Default as Provider>::Client;
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn start_server(self) -> Result<Self::Server, Self::Error> {
        let empty_cert = &[][..];
        let server = default::Server::builder()
            .with_certificate(empty_cert, self)?
            .build()?;
        Ok(server)
    }
    fn start_client(self) -> Result<Self::Client, Self::Error> {
        let client = default::Client::builder().with_certificate(self)?.build()?;
        Ok(client)
    }
}
impl Provider for (&str, &str) {
    type Server = <Default as Provider>::Server;
    type Client = <Default as Provider>::Client;
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn start_server(self) -> Result<Self::Server, Self::Error> {
        let server = default::Server::builder()
            .with_certificate(self.0, self.1)?
            .build()?;
        Ok(server)
    }
    fn start_client(self) -> Result<Self::Client, Self::Error> {
        let client = default::Client::builder()
            .with_certificate(self.0)?
            .build()?;
        Ok(client)
    }
}
impl Provider for &str {
    type Server = <Default as Provider>::Server;
    type Client = <Default as Provider>::Client;
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn start_server(self) -> Result<Self::Server, Self::Error> {
        let empty_cert = "";
        let server = default::Server::builder()
            .with_certificate(empty_cert, self)?
            .build()?;
        Ok(server)
    }
    fn start_client(self) -> Result<Self::Client, Self::Error> {
        let client = default::Client::builder().with_certificate(self)?.build()?;
        Ok(client)
    }
}
#[cfg(feature = "provider-tls-default")]
mod default_tls {
    pub use s2n_quic_tls_default::*;
    #[cfg(not(any(
        all(not(unix), feature = "s2n-quic-rustls"),
        all(unix, feature = "s2n-quic-tls")
    )))]
    mod default_provider {
        use super::*;
        use crate::provider::tls;
        impl tls::Provider for Server {
            type Server = Self;
            type Client = Client;
            type Error = core::convert::Infallible;
            fn start_server(self) -> Result<Self::Server, Self::Error> {
                Ok(self)
            }
            fn start_client(self) -> Result<Self::Client, Self::Error> {
                panic!("cannot create a client from a server");
            }
        }
        impl tls::Provider for Client {
            type Server = Server;
            type Client = Self;
            type Error = core::convert::Infallible;
            fn start_server(self) -> Result<Self::Server, Self::Error> {
                panic!("cannot create a server from a client");
            }
            fn start_client(self) -> Result<Self::Client, Self::Error> {
                Ok(self)
            }
        }
    }
}
#[cfg(not(feature = "provider-tls-default"))]
mod default_tls {
    }
#[cfg(feature = "s2n-quic-rustls")]
pub mod rustls {
    pub use s2n_quic_rustls::*;
    impl super::Provider for Server {
        type Server = Self;
        type Client = Client;
        type Error = core::convert::Infallible;
        fn start_server(self) -> Result<Self::Server, Self::Error> {
            Ok(self)
        }
        fn start_client(self) -> Result<Self::Client, Self::Error> {
            panic!("cannot create a client from a server");
        }
    }
    impl super::Provider for Client {
        type Server = Server;
        type Client = Self;
        type Error = core::convert::Infallible;
        fn start_server(self) -> Result<Self::Server, Self::Error> {
            panic!("cannot create a server from a client");
        }
        fn start_client(self) -> Result<Self::Client, Self::Error> {
            Ok(self)
        }
    }
}
#[cfg(feature = "s2n-quic-tls")]
pub mod s2n_tls {
    pub use s2n_quic_tls::*;
    impl<L: ConfigLoader> super::Provider for Server<L> {
        type Server = Self;
        type Client = Client;
        type Error = core::convert::Infallible;
        fn start_server(self) -> Result<Self::Server, Self::Error> {
            Ok(self)
        }
        fn start_client(self) -> Result<Self::Client, Self::Error> {
            panic!("cannot create a client from a server");
        }
    }
    impl<L: ConfigLoader> super::Provider for Client<L> {
        type Server = Server;
        type Client = Self;
        type Error = core::convert::Infallible;
        fn start_server(self) -> Result<Self::Server, Self::Error> {
            panic!("cannot create a server from a client");
        }
        fn start_client(self) -> Result<Self::Client, Self::Error> {
            Ok(self)
        }
    }
}