use std::io::{Error, ErrorKind, Read, Write};
use std::net::TcpStream;
use openssl::ssl::{SslConnector, SslMethod};

pub enum Server {
    StreamTls(openssl::ssl::SslStream<TcpStream>),
    Stream(TcpStream),
}

impl Server {
    pub fn new(host: String, port: u16) -> Result<Server, Error> {
        let ssl = if port == 993 {
            true
        } else {
            false
        };

        // 创建一个 OpenSSL SSL 连接器
        let connector = SslConnector::builder(SslMethod::tls())?.build();

        let res = match TcpStream::connect(format!("{}:{}", host, port)) {
            Ok(stream) => {
                if ssl {

                    // 通过 SSL 连接到服务器
                    let ssl_stream = connector.connect(host.as_str(), stream).unwrap();

                    //
                    // let root_store = RootCertStore::from_iter(
                    //     webpki_roots::TLS_SERVER_ROOTS
                    //         .iter()
                    //         .cloned(),
                    // );
                    //
                    // let config = rustls::ClientConfig::builder()
                    //     .with_root_certificates(root_store)
                    //     .with_no_client_auth();
                    //
                    // let server_name = host.try_into().unwrap();
                    // let connection = match ClientConnection::new(Arc::new(config), server_name) {
                    //     Ok(e) => e,
                    //     Err(e) => return Err(Error::new(ErrorKind::Other, format!("连接加载失败: {}", e.to_string())))
                    // };


                    /*   Server::StreamTls(StreamOwned::new(connection, stream))*/

                    Server::StreamTls(ssl_stream)
                } else {
                    Server::Stream(stream)
                }
            }
            Err(e) => return Err(Error::new(ErrorKind::Other, format!("连接加载失败: {}", e.to_string())))
        };
        Ok(res)
    }
    pub fn login(&mut self, name: String, pass: String) -> Result<(), Error> {
        self.read()?;
        self.write(format!("a001 LOGIN {} {}\r\n", name, pass).as_bytes(), false)?;
        Ok(())
    }

    fn write(&mut self, data: &[u8], long: bool) -> Result<String, Error> {
        let res = match self {
            Server::StreamTls(e) => e.write(data),
            Server::Stream(e) => e.write(data),
        };
        match res {
            Ok(_) => {
                match long {
                    true => Ok(self.read_multi()?),
                    false => {
                        let res = self.read()?;
                        Ok(res.trim().to_string())
                    }
                }
            }
            Err(e) => Err(Error::new(ErrorKind::Other, format!("写入失败: {}", e.to_string())))
        }
    }

    fn read(&mut self) -> Result<String, Error> {
        let res = match self {
            Server::StreamTls(e) => read(e)?,
            Server::Stream(e) => read(e)?
        };
        Ok(res)
    }

    fn read_multi(&mut self) -> Result<String, Error> {
        let res = match self {
            Server::StreamTls(e) => read_multi(e)?,
            Server::Stream(e) => read_multi(e)?
        };
        Ok(res)
    }

    pub fn total(&mut self) -> Result<usize, Error> {
        let res = self.write(format!("a001 SELECT INBOX\r\n").as_bytes(), false)?;
        let mut count = 0;
        for line in res.leak().lines() {
            if line.ends_with("EXISTS") {
                count = line.trim_start_matches("*").trim_end_matches("EXISTS").trim().parse().unwrap();
            }
        }
        Ok(count)
    }

    pub fn select(&mut self) -> Result<Vec<String>, Error> {
        self.write(format!("a001 SELECT INBOX\r\n").as_bytes(), false)?;
        let res = self.write(format!("a002 UID FETCH 1:* (UID)\r\n").as_bytes(), true)?;
        let lines = res.leak().lines();
        let mut ids = vec![];
        for line in lines {
            if line.contains("OK") {
                continue;
            }
            let t = line.split("FETCH").collect::<Vec<&str>>();
            let li = t[0].trim_start_matches("*").trim().to_string();
            // let t = line.split("UID").collect::<Vec<&str>>();
            // let li = t[1].trim_end_matches(")").trim();
            ids.push(li)
        }
        Ok(ids)
    }
    /// 获取详细信息
    pub fn info(&mut self, id: &str) -> Result<Vec<u8>, Error> {
        self.write(format!("a001 SELECT INBOX\r\n").as_bytes(), false)?;
        let res = self.write(format!("a002 FETCH {id} (BODY[])\r\n").as_bytes(), true)?;
        let res = match res.find("\r\n") {
            None => return Err(Error::new(ErrorKind::Other, format!("读取内容失败: {}", res.to_string()))),
            Some(e) => &res[e + 2..].to_string()
        };
        let res = match res.rfind(")") {
            None => return Err(Error::new(ErrorKind::Other, format!("读取内容失败: {}", res.to_string()))),
            Some(e) => &res[..e].to_string()
        };
        Ok(res.as_bytes().to_vec())
    }

    /// 删除邮件
    pub fn delete(&mut self, id: &str) -> Result<bool, Error> {
        self.write(format!("a001 SELECT INBOX\r\n").as_bytes(), false)?;

        let res = self.write(format!("a002 STORE {} +FLAGS (\\Deleted)\r\n", id).as_bytes(), false)?;
        let lines = res.leak().lines();
        for line in lines {
            if line.contains("NO") {
                return Ok(false);
            }
        }
        return Ok(true);
        // let res = self.write(format!("a003 EXPUNGE\r\n").as_bytes(), false)?;
        // let mut lines = res.leak().lines();
        // for line in lines {
        //     if line.contains("OK EXPUNGE Done") {
        //         return Ok(true);
        //     }
        // }
        // Ok(false)
    }
}
fn read_multi(reader: &mut impl Read) -> Result<String, Error> {
    let mut data = vec![];
    loop {
        let mut buffer = [0u8; 1024 * 1024];
        match reader.read(&mut buffer) {
            Ok(e) => data.extend(buffer[..e].to_vec()),
            Err(e) => return Err(Error::new(ErrorKind::Other, format!("读取失败: {}", e.to_string())))
        }
        if data.ends_with("OK FETCH Completed\r\n".as_bytes())
            || data.ends_with("OK UID FETCH Completed\r\n".as_bytes())
            || data.ends_with("not exist!\r\n".as_bytes())
        {
            break;
        }
    }
    let str = unsafe { String::from_utf8_unchecked(data) };
    Ok(str)
}

fn read(reader: &mut impl Read) -> Result<String, Error> {
    let mut data = vec![];
    loop {
        let mut buffer = [0u8; 1024];
        match reader.read(&mut buffer) {
            Ok(e) => {
                data.extend(buffer[..e].to_vec());
            }
            Err(e) => return Err(Error::new(ErrorKind::Other, format!("读取失败: {}", e.to_string())))
        }
        if data.ends_with(&[13, 10]) {
            break;
        }
    }
    let str = unsafe { String::from_utf8_unchecked(data) };
    Ok(str.trim().to_string())
}
