use std::fs::File;
use std::time::Duration;
use curl::easy::{Easy, List};
use json::{JsonValue, object};
use std::io::{Read, Write};
use std::str;
use log::info;
use xml2json_rs::{JsonConfig};


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.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
    }

    /// 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.read_function(|data| {
                let res = self.body.as_bytes().read(data).unwrap();
                Ok(res)
            }).unwrap();

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

            match transfer.perform() {
                Ok(_) => {
                    ()
                }
                Err(e) => {
                    info!("url 执行错误: {}",e.to_string());
                }
            }
        }
        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());
                    let mut file = File::create(self.filepath.as_str()).unwrap();
                    file.write(&body).unwrap();
                    let res = br_file::is_file(self.filepath.as_str());
                    return JsonValue::Boolean(res);
                } else {
                    return JsonValue::Boolean(false);
                }
            }
            _ => {
                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"] = "text".into();
            }
            "null" => {
                self.res_headers["type"] = "null".into();
            }
            _ => {
                info!("未知类型: {:#?}", data);
                self.res_headers["type"] = "text".into();
            }
        }
    }
}