use std::{
    io::{self, Read, Write},
    net::{SocketAddr, TcpStream},
    time::Duration,
};

use crate::connection::{HttpConnection, HttpConnectionOptions, HttpConnector};

pub struct TcpConnector;

impl HttpConnector for TcpConnector {
    type Connection = TcpStream;
    type Error = io::Error;

    fn connect(
        &mut self,
        remote: &SocketAddr,
        scheme: &str,
        server_name: &str,
        timeout: Option<Duration>,
        options: HttpConnectionOptions,
    ) -> Result<Self::Connection, Self::Error> {
        let _ = (scheme, server_name);
        let socket = match timeout {
            Some(timeout) => TcpStream::connect_timeout(remote, timeout)?,
            None => TcpStream::connect(remote)?,
        };
        socket.set_read_timeout(options.read_timeout)?;
        socket.set_write_timeout(options.write_timeout)?;
        Ok(socket)
    }

    fn default_port(&self, scheme: &str) -> u16 {
        let _ = scheme;
        80
    }

    fn supports_scheme(&self, scheme: &str) -> bool {
        scheme.eq_ignore_ascii_case("http")
    }
}

impl HttpConnection for TcpStream {
    type Error = io::Error;

    fn send(&mut self, buffer: &[u8]) -> Result<usize, Self::Error> {
        self.write(buffer)
    }

    fn send_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
        self.write_all(buffer)
    }

    fn recv(&mut self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
        self.read(buffer)
    }

    fn recv_exact(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
        self.read_exact(buffer)
    }
}
