pub mod request;
pub mod response;

use std::time::Duration;
use json::{JsonValue, object};
use std::io::{Read, Write};
use std::net::{TcpStream};
use std::str;
use log::info;

use crate::request::{FormData, Request};
use crate::response::Response;

#[derive(Debug)]
pub struct Client {
    debug: bool,
    request: Request,
    response: Response,
    read_timeout: u64,
    write_timeout: u64,
}

impl Client {
    pub fn new() -> Client {
        Self {
            debug: false,
            request: Request::default(),
            response: Response::default(),
            read_timeout: 5,
            write_timeout: 5,
        }
    }
    pub fn set_read_timeout(&mut self, secs: u64) -> &mut Client {
        self.read_timeout = secs;
        self
    }
    pub fn set_write_timeout(&mut self, secs: u64) -> &mut Client {
        self.write_timeout = secs;
        self
    }
    pub fn set_version(&mut self, name: &str) -> &mut Client {
        self.request.version = Version::set_version(name);
        self
    }
    /// 调试
    pub fn debug(&mut self, open: bool) -> &mut Client {
        self.debug = open;
        self
    }
    /// GET请求
    pub fn get(&mut self, url: &str) -> &mut Client {
        self.request.set_method(Method::Get);
        self.request.set_url(url);
        self
    }
    /// POST请求
    pub fn post(&mut self, url: &str) -> &mut Client {
        self.request.set_method(Method::Post);
        self.request.set_url(url);
        self
    }
    pub fn options(&mut self, url: &str) -> &mut Client {
        self.request.set_method(Method::Options);
        self.request.set_url(url);
        self
    }
    pub fn patch(&mut self, url: &str) -> &mut Client {
        self.request.set_method(Method::Patch);
        self.request.set_url(url);
        self
    }
    pub fn head(&mut self, url: &str) -> &mut Client {
        self.request.set_method(Method::Head);
        self.request.set_url(url);
        self
    }
    pub fn delete(&mut self, url: &str) -> &mut Client {
        self.request.set_method(Method::Delete);
        self.request.set_url(url);
        self
    }

    pub fn header(&mut self, key: &str, value: &str) -> &mut Client {
        self.request.set_header(key, value);
        self
    }
    /// bearer 登陆头
    pub fn authorization_bearer(&mut self, token: &str) -> &mut Client {
        self.header("Authorization", format!("Bearer {}", token).as_str());
        self
    }
    pub fn cookie(&mut self, key: &str, value: &str) -> &mut Client {
        self.request.set_header("Cookie", format!("{}={}", key, value).as_str());
        self
    }
    /// query 请求地址参数
    pub fn query(&mut self, mut data: JsonValue) -> &mut Client {
        let mut t = vec![];
        for (key, value) in data.entries_mut() {
            t.push(format!("{}={}", key, value))
        };
        self.request.set_query(t.join("&").as_str());
        self
    }
    /// form-data 数据类型
    pub fn form_data(&mut self, data: Vec<FormData>) -> &mut Client {
        self.request.set_body_form_data(data);
        self
    }
    /// form 数据类型
    pub fn form(&mut self, data: JsonValue) -> &mut Client {
        self.request.set_body_form(data);
        self
    }
    /// json 数据类型
    pub fn raw_json(&mut self, data: JsonValue) -> &mut Client {
        self.request.set_body_json(data);
        self
    }
    pub fn raw_xml(&mut self, data: &str) -> &mut Client {
        self.request.set_body_xml(data);
        self
    }
    pub fn raw_html(&mut self) -> &mut Client {
        self.request.set_body_html();
        self
    }
    /// 发送回执
    pub fn send(&mut self) -> Result<&mut Self, String> {
        let stream = TcpStream::connect(self.request.host.clone());
        let mut stream = match stream {
            Ok(stream) => stream,
            Err(e) => return Err(e.to_string())
        };

        stream.set_read_timeout(Option::from(Duration::from_secs(self.read_timeout))).unwrap();
        stream.set_write_timeout(Option::from(Duration::from_secs(self.write_timeout))).unwrap();

        // 发送数据到服务器
        let header = self.request.header();
        let body = self.request.body();
        if self.debug {
            info!("请求数据: {}://{} \r\n", self.request.scheme, self.request.url);
            info!("========================请求内容⬇️=================================");
            info!("{}{}", header, String::from_utf8_lossy(&*body.clone()));
            info!("========================请求内容⬆️=================================");
        }
        let mut buf = header.as_bytes().to_vec();
        buf.extend(body);
        match stream.write_all(&*buf) {
            Ok(_) => {}
            Err(e) => return Err(e.to_string())
        };

        // 接收响应数据
        let mut buffers = Vec::new();
        let mut len = 0;
        let mut body = 0;
        let mut is_body = false;
        if self.debug {
            info!("开始监听回执");
        }
        loop {
            let mut buffer = [0u8; 1024];
            let r = match stream.read(&mut buffer) {
                Ok(e) => e,
                Err(e) => return Err(format!("读取失败: {} {:?}", e.to_string(),buffers))
            };
            if r == 0 {
                info!("协议格式异常");
                break;
            }
            let received_data = String::from_utf8_lossy(&buffer[..r]);
            if !is_body {
                for line in received_data.lines() {
                    if line.starts_with("Content-Length: ") {
                        len = match line.strip_prefix("Content-Length: ") {
                            None => 0,
                            Some(e) => e.parse::<usize>().unwrap()
                        };
                        continue;
                    }
                    if line == "" {
                        is_body = true;
                        continue;
                    }
                    if is_body {
                        body += line.len();
                    }
                }
            } else {
                body += r;
            }
            buffers.extend(buffer[..r].to_vec());
            if is_body {
                if len == body || len==0{
                    break;
                }
            }
        }

        let received_data = String::from_utf8_lossy(&buffers);

        self.response.new(received_data.clone());
        if self.debug {
            info!("========================响应内容⬇️=================================");
            info!("{} {}", self.response.status.clone(), self.response.version.clone().str());
            info!("{}", received_data);
            info!("========================响应内容⬆️=================================");
        }
        if self.response.status!=200{
            return match self.response.status {
                301 => {
                    let r = match self.send() {
                        Ok(e) => e,
                        Err(e) => {
                            return Err(e);
                        }
                    };
                    Ok(r)
                }
                _ => {
                    Err(format!("{} {}", self.response.status, self.response.err))
                }
            }
        }
        Ok(self)
    }
    /// 返回 text
    pub fn text(&mut self) -> String {
        self.response.body.clone()
    }
    /// 返回 text
    pub fn json(&mut self) -> JsonValue {
        match json::parse(&*self.response.body.clone()) {
            Ok(e) => e,
            Err(_) => object! {}
        }
    }
}


#[derive(Debug)]
pub enum Method {
    Options,
    Get,
    Post,
    Put,
    Delete,
    Head,
    Trace,
    Connect,
    Patch,
}

impl Method {
    pub fn str(&mut self) -> &'static str {
        match self {
            Method::Options => "OPTIONS",
            Method::Get => "GET",
            Method::Post => "POST",
            Method::Put => "PUT",
            Method::Delete => "DELETE",
            Method::Head => "HEAD",
            Method::Trace => "TRACE",
            Method::Connect => "CONNECT",
            Method::Patch => "PATCH"
        }
    }
}

#[derive(Clone, Debug)]
pub enum Version {
    Http09,
    Http10,
    Http11,
    H2,
    H3,
    None,
}

impl Version {
    pub fn str(&mut self) -> &'static str {
        match self {
            Version::Http09 => "HTTP/0.9",
            Version::Http10 => "HTTP/1.0",
            Version::Http11 => "HTTP/1.1",
            Version::H2 => "HTTP/2.0",
            Version::H3 => "HTTP/3.0",
            Version::None => ""
        }
    }
    pub fn from(name: &str) -> Version {
        match name {
            "HTTP/0.9" => Self::Http09,
            "HTTP/1.0" => Self::Http10,
            "HTTP/1.1" => Self::Http11,
            "HTTP/2.0" => Self::H2,
            "HTTP/3.0" => Self::H3,
            _ => Self::None
        }
    }
    pub fn set_version(name: &str) -> Version {
        match name {
            "0.9" => Self::Http09,
            "1.0" => Self::Http10,
            "1.1" => Self::Http11,
            "2.0" => Self::H2,
            "3.0" => Self::H3,
            _ => Self::None
        }
    }
}

#[derive(Clone, Debug)]
pub enum ContentType {
    Html,
    Text,
    Json,
    Xml,
    OctetStream,
    FormData,
    XWwwFormUrlencoded,
    None,
}

impl ContentType {
    pub fn from(name: &str) -> ContentType {
        match name {
            "text/html" => Self::Html,
            "text/plain" => Self::Text,
            "application/json" => Self::Json,
            "application/xml" => Self::Xml,
            "application/octet-stream" => Self::OctetStream,
            "multipart/form-data" => Self::FormData,
            "application/x-www-form-urlencoded" => Self::XWwwFormUrlencoded,
            _ => Self::None
        }
    }
    pub fn str(self) -> &'static str {
        match self {
            ContentType::Html => "text/html",
            ContentType::Xml => "application/xml",
            ContentType::Json => "application/json",
            ContentType::OctetStream => "application/octet-stream",
            ContentType::FormData => "multipart/form-data",
            ContentType::XWwwFormUrlencoded => "application/x-www-form-urlencoded",
            ContentType::None | ContentType::Text => "text/plain"
        }
    }
}