pub mod request;
mod response;

use std::fs::File;
use std::time::Duration;
use curl::easy::{Easy, List};
use json::{JsonValue, object};
use std::io::{Error, Read, Write};
use std::net::{AddrParseError, SocketAddr, TcpStream};
use std::path::PathBuf;
use std::str;
use std::str::FromStr;
use log::info;
use xml2json_rs::{JsonConfig};
use crate::request::{FormData, Request};
use crate::response::Response;


pub struct Http {
    url: String,
    curl: Easy,
    body: String,
    headers: Vec<String>,
    cookies: Vec<String>,
    pub res_headers: JsonValue,
    filepath: String,
    pub res_cookies: JsonValue,
    head: bool,
}

impl Http {
    /// 请求地址
    pub fn url(url: &str) -> Self {
        Self {
            url: url.to_string(),
            curl: Easy::new(),
            body: String::new(),
            headers: Vec::new(),
            cookies: Vec::new(),
            res_headers: object! {},
            filepath: String::new(),
            res_cookies: object! {},
            head: false,
        }
    }
    /// Bearer认证
    pub fn authorization_bearer(&mut self, token: &str) -> &mut Self {
        self.set_headers("Authorization", format!("Bearer {}", token).as_str());
        self
    }
    /// auth认证
    pub fn authorization(&mut self, token: &str) -> &mut Self {
        self.set_headers("Authorization", format!("{}", token).as_str());
        self
    }
    /// 调试
    /// 控制台将输出大量的信息以供
    pub fn debug(&mut self) -> &mut Self {
        self.curl.verbose(true).unwrap();
        self
    }
    /// 是否显示进程表
    pub fn progress(&mut self, open: bool) -> &mut Self {
        self.curl.progress(open).unwrap();
        let mut i = 0.0;
        self.curl.progress_function(move |total_download_bytes, cur_download_bytes, _total_upload_bytes, _cur_upload_bytes| {
            if total_download_bytes > 0.0 {
                if i != cur_download_bytes / total_download_bytes * 100.0 {
                    i = cur_download_bytes / total_download_bytes * 100.0;
                    info!("已下载:{}%", i);
                }
            } else {
                if i > 0.0 {} else {
                    i = 1.0;
                    info!("已下载:0%");
                }
            }
            true
        }).expect("进度执行失败");
        self
    }
    /// 设置头信息
    pub fn set_headers(&mut self, key: &str, value: &str) -> &mut Self {
        self.headers.push(format!("{}: {}", key, value));
        self
    }
    /// 设置cookie
    pub fn set_cookies(&mut self, key: &str, value: &str) -> &mut Self {
        self.cookies.push(format!("{}={}", key, value));
        self
    }
    /// 设置认证账号
    pub fn auth(&mut self, username: &str, password: &str) -> &mut Self {
        self.curl.username(username).unwrap();
        self.curl.password(password).unwrap();
        self
    }
    /// PUT 发送
    pub fn put(&mut self, data: JsonValue) -> &mut Self {
        self.curl.custom_request("PUT").unwrap();
        self.body = data.to_string();
        self.curl.upload_buffer_size(self.body.as_bytes().len()).unwrap();
        self.curl.post_field_size(self.body.as_bytes().len() as u64).unwrap();
        self
    }
    /// POST 发送
    pub fn post(&mut self, data: JsonValue) -> &mut Self {
        self.body = data.dump();
        self.curl.post(true).unwrap();
        self.curl.post_field_size(self.body.as_bytes().len() as u64).unwrap();
        self
    }

    /// POST 发送
    pub fn post_form_data(&mut self, data: JsonValue) -> &mut Self {
        self.set_headers("Content-Type", "multipart/form-data");
        self.body = data.dump();
        self.curl.post(true).unwrap();
        self.curl.post_field_size(self.body.as_bytes().len() as u64).unwrap();
        self
    }

    pub fn post_form_urlencoded(&mut self, data: JsonValue) -> &mut Self {
        self.set_headers("Content-Type", "application/x-www-form-urlencoded");
        let mut post = vec![];
        for (key, value) in data.entries() {
            post.push(format!("{}={}", key, value));
        }
        self.body = post.join("&");
        self.curl.post(true).unwrap();
        self.curl.upload_buffer_size(self.body.as_bytes().len()).unwrap();
        self.curl.post_field_size(self.body.as_bytes().len() as u64).unwrap();
        self
    }

    /// POST json 发送
    pub fn post_json(&mut self, data: JsonValue) -> &mut Self {
        self.set_headers("content-type", "application/json");
        self.body = data.dump();
        self.curl.post(true).unwrap();
        self.curl.post_field_size(self.body.as_bytes().len() as u64).unwrap();

        self
    }
    /// patch 请求
    pub fn patch(&mut self, body: JsonValue) -> &mut Self {
        self.curl.custom_request("patch").unwrap();
        self.set_headers("content-type", "application/json");
        self.body = body.dump();
        self.curl.post_field_size(self.body.as_bytes().len() as u64).unwrap();
        self
    }
    /// custom 请求
    pub fn custom(&mut self, custom: &str, body: JsonValue) -> &mut Self {
        self.curl.custom_request(custom).unwrap();
        self.body = body.dump();
        self
    }
    /// GET 请求
    pub fn get(&mut self, data: JsonValue) -> &mut Self {
        self.curl.get(true).unwrap();
        if !data.is_empty() {
            let mut url = "".to_string();
            for (k, v) in data.entries() {
                if url == "" {
                    url = format!("{}={}", k, v);
                } else {
                    url = format!("{}&{}={}", url, k, v);
                }
            }
            self.url = format!("{}?{}", self.url, url);
        }
        self
    }
    /// head 请求
    pub fn head(&mut self, data: JsonValue) -> &mut Self {
        self.curl.custom_request("head").unwrap();
        self.head = true;
        self.curl.nobody(true).unwrap();
        if !data.is_empty() {
            self.body = data.dump();
            self.curl.post_field_size(self.body.as_bytes().len() as u64).unwrap();
        }
        self
    }
    /// download 下载
    pub fn download(&mut self, filepath: &str) -> &mut Self {
        self.filepath = filepath.to_string();
        self
    }
    /// 返回
    pub fn response(&mut self) -> JsonValue {
        if !self.headers.is_empty() {
            let mut headers = List::new();
            for header in self.headers.clone() {
                headers.append(header.as_str()).unwrap();
            }
            self.curl.http_headers(headers).unwrap();
        }

        if !self.cookies.is_empty() {
            let mut cookies = "".to_string();
            for cookie in self.cookies.clone() {
                if cookies == "" {
                    cookies = format!("{}", cookie);
                } else {
                    cookies = format!("{};{}", cookies, cookie);
                }
            }
            self.curl.cookie(&*cookies).unwrap();
        }
        self.curl.accept_encoding("zlib,gzip,identity").unwrap();
        self.curl.timeout(Duration::from_micros(5)).unwrap();
        self.curl.connect_timeout(Duration::from_micros(5)).unwrap();

        self.curl.url(self.url.as_str()).unwrap();

        let mut body = Vec::new();
        {
            let mut transfer = self.curl.transfer();

            transfer.header_function(|data| {
                let str = str::from_utf8(data).unwrap();
                let data: Vec<&str> = str.split(":").collect();
                let key = data[0].to_lowercase();
                match key.as_str() {
                    "set-cookie" => {
                        let kv: Vec<&str> = data[1].split(";").collect();
                        let cookie = kv[0].trim();
                        let kv: Vec<&str> = cookie.split("=").collect();
                        for index in 0..kv.len() {
                            let k = kv[0].clone();
                            if index == 0 {
                                self.res_cookies[k] = "".into();
                            } else {
                                if kv[index] == "" {
                                    self.res_cookies[k] = format!("{}=", self.res_cookies[k]).into();
                                } else {
                                    self.res_cookies[k] = format!("{}", kv[index]).into();
                                }
                            }
                        }
                    }
                    _ => {
                        if data.len() > 1 {
                            self.res_headers[key.as_str()] = data[1].trim_start_matches(" ").trim_end_matches("\r\n").trim_start_matches('\"').trim_end_matches('\"').into();
                        }
                    }
                }
                true
            }).unwrap();

            transfer.write_function(|data| {
                body.extend(data.clone());
                Ok(data.len())
            }).unwrap();

            transfer.read_function(|data| {
                let res = self.body.as_bytes().read(data).unwrap();
                Ok(res)
            }).unwrap();


            match transfer.perform() {
                Ok(_) => {
                    ()
                }
                Err(e) => {
                    info!("url 执行错误: {} {}",e.to_string(), self.url);
                    return object! {};
                }
            }
        }

        self._state();
        let data = String::from_utf8_lossy(&body);
        let data = &data as &str;

        match self.res_headers["type"].as_str().unwrap() {
            "json" => {
                return json::parse(data).unwrap();
            }
            "text" => {
                return JsonValue::from(data);
            }
            "null" => {
                return self.res_headers.clone();
            }
            "pdf" => {
                if data.is_empty() {
                    if self.head {
                        return self.res_headers.clone();
                    }
                    return JsonValue::from("");
                }
                let base64 = br_crypto::base64::encode_file(data.as_bytes().to_vec());
                return JsonValue::from(base64);
            }
            "xml" => {
                if data.is_empty() {
                    if self.head {
                        return self.res_headers.clone();
                    }
                    return JsonValue::from("");
                }
                let json_builder = JsonConfig::new()
                    .ignore_attrs(true)
                    .explicit_array(false)
                    .finalize();
                let json = json_builder.build_string_from_xml(data).unwrap_or("".to_string());
                let data = json::parse(&*json).unwrap();
                return JsonValue::from(data);
            }
            "jpeg" => {
                if !self.filepath.is_empty() {
                    br_file::create_dir(self.filepath.as_str()).unwrap();
                    let mut file = File::create(self.filepath.as_str()).unwrap();
                    file.write(&body).unwrap();
                    let res = PathBuf::from(self.filepath.as_str());
                    let res = res.is_file();
                    return JsonValue::Boolean(res);
                } else {
                    return JsonValue::Boolean(false);
                }
            }
            "stream" => {
                let body = unsafe { String::from_utf8_unchecked(body) };
                return JsonValue::from(body);
            }
            _ => {
                info!("非法请求: {:#}", self.res_headers);
            }
        }
        return object! {};
    }
    /// 状态处理
    fn _state(&mut self) {
        self.res_headers["code"] = self.curl.response_code().unwrap().into();
        self.res_headers["content-type"] = self.curl.content_type().unwrap().into();
        let content_type = self.res_headers["content-type"].to_string();
        let data: Vec<&str> = content_type.split(";").collect();
        match data[0] {
            "application/json" => {
                self.res_headers["type"] = "json".into();
            }
            "text/html" | "text/plain" => {
                self.res_headers["type"] = "text".into();
            }
            "image/jpeg" => {
                self.res_headers["type"] = "jpeg".into();
            }
            "application/xml" | "text/xml" => {
                self.res_headers["type"] = "xml".into();
            }
            "application/pdf" => {
                self.res_headers["type"] = "pdf".into();
            }
            "application/octet-stream" => {
                self.res_headers["type"] = "stream".into();
            }
            "null" => {
                self.res_headers["type"] = "null".into();
            }
            _ => {
                info!("未知类型: {:#?}", data);
                self.res_headers["type"] = "text".into();
            }
        }
    }
}


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

impl Client {
    pub fn new() -> Client {
        Self {
            debug: false,
            request: Request::default(),
            response: Response::default(),
        }
    }
    /// 调试
    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
    }
    pub fn cookie(&mut self, key: &str, value: &str) -> &mut Client {
        self.request.set_header("Cookie", format!("{}={}", key, value).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 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(5))).unwrap();
        stream.set_write_timeout(Option::from(Duration::from_secs(5))).unwrap();

        // 发送数据到服务器
        let header = self.request.header();
        let body = self.request.body();
        if self.debug {
            println!("请求数据: {}://{} \n", self.request.scheme, self.request.url);
            unsafe { println!("{}{}", header, String::from_utf8_unchecked(body.clone())); }
            println!("=========================================================");
        }
        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 buffer = vec![];
        let r = match stream.read_to_end(&mut buffer) {
            Ok(e) => e,
            Err(e) => return Err(e.to_string())
        };
        let received_data = String::from_utf8_lossy(&buffer[..r]);
        self.response.new(received_data.clone());
        if self.debug {
            println!("响应数据: {} {}", self.response.status.clone(), self.response.version.clone().str());
            println!("{}", received_data);
        }

        Ok(self)
    }

    pub fn text(&mut self) -> String {
        self.response.body.clone()
    }
    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/1.1" => Self::Http11,
            "HTTP/1.0" => Self::Http10,
            "HTTP/0.9" => Self::Http09,
            "HTTP/2.0" => Self::H2,
            "HTTP/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"
        }
    }
}