use std::collections::HashMap;
use std::fmt::Debug;
use std::fs;
use br_crypto::encoding::{urlencoding_encode};
use json::JsonValue;
use log::{error};
use url::Url;
use crate::{ContentType, Method, Version};

/// 请求
#[derive(Debug)]
pub struct Request {
    method: Method,
    pub version: Version,
    pub(crate) scheme: String,
    pub(crate) domain: String,
    pub host: String,
    pub port: u16,
    path: String,
    pub url: String,
    headers: HashMap<String, String>,
    pub body: Body,
    content_type: ContentType,
    query: String,
}

impl Request {
    pub fn default() -> Self {
        Self {
            method: Method::Get,
            scheme: String::new(),
            host: String::new(),
            path: String::new(),
            url: String::new(),
            domain: String::new(),
            port: 0,
            headers: Default::default(),
            body: Body::default(),
            version: Version::Http11,
            content_type: ContentType::Html,
            query: "".to_string(),
        }
    }
    pub fn set_method(&mut self, method: Method) {
        self.method = method;
    }
    pub fn set_version(&mut self, name: &str) {
        self.version = Version::set_version(name)
    }
    pub fn set_header(&mut self, key: &str, value: &str) {
        self.headers.insert(key.to_string(), value.to_string());
    }
    pub fn set_query(&mut self, data: &str) {
        if self.query.is_empty() {
            self.query = data.to_string();
        } else {
            self.query = format!("{}&{}", self.query, data);
        }
    }
    pub fn set_url(&mut self, url: &str) {
        match Url::parse(url.clone()) {
            Ok(urls) => {
                // 获取 URL 的各个部分
                self.scheme = urls.scheme().to_string();
                self.domain = urls.host_str().unwrap_or("").to_string();
                self.path = urls.path().to_string();
                self.port = urls.port().unwrap_or(80);
                self.query = urls.query().unwrap_or("").to_string();
                self.url = url.strip_prefix(format!("{}://{}", self.scheme, self.host).as_str()).unwrap().to_string();
                self.host = format!("{}:{}", self.domain.as_str(), self.port);
            }
            Err(e) => {
                error!("Failed to parse URL: {}", e.to_string());
            }
        }
    }

    pub fn set_body_json(&mut self, data: JsonValue) {
        self.content_type = ContentType::Json;
        self.set_header("Content-Type", self.content_type.clone().str());
        self.set_header("Content-Length", format!("{}", data.to_string().len()).as_str());
        self.body = Body::Json(data);
    }
    pub fn set_body_xml(&mut self, data: &str) {
        self.content_type = ContentType::Xml;
        self.set_header("Content-Type", self.content_type.clone().str());
        self.set_header("Content-Length", format!("{}", data.len()).as_str());
        self.body = Body::Xml(data.to_string());
    }
    pub fn set_body_html(&mut self) {
        self.content_type = ContentType::Html;
        self.set_header("Content-Type", self.content_type.clone().str());
        self.body = Body::None;
    }
    pub fn set_body_form_data(&mut self, data: Vec<FormData>) {
        self.content_type = ContentType::FormData;
        let boundary = format!("----------{}", chrono::Utc::now().timestamp_millis());
        let mut body = Vec::new();
        for field in data.iter() {
            body.extend(format!("--{}\r\n", boundary).as_bytes());
            match field {
                FormData::Text(key, value) => {
                    // 添加文本字段
                    body.extend(format!("Content-Disposition: form-data; name=\"{}\"\r\n\r\n{}", key, value).as_bytes());
                }
                FormData::File(key, filename, path) => {
                    // 添加文件字段
                    body.extend(format!("Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n", key, filename).as_bytes());
                    body.extend(format!("Content-Type: application/octet-stream\r\n\r\n").as_bytes());
                    // 读取文件内容
                    match fs::read(path) {
                        Ok(file_content) => {
                            body.extend(file_content);
                        }
                        Err(_) => {
                            body.extend::<Vec<u8>>(vec![]);
                        }
                    }
                }
            }
        }
        // 添加 form-data 结束标志
        body.extend(format!("\r\n--{}--\r\n", boundary).as_bytes());
        self.set_header("Content-Type", format!("{}; boundary={}", self.content_type.clone().str(), boundary).as_str());
        self.set_header("Content-Length", format!("{}", body.len()).as_str());
        self.body = Body::FormData(body);
    }
    pub fn set_body_form(&mut self, data: JsonValue) {
        self.content_type = ContentType::XWwwFormUrlencoded;
        let mut body = Vec::new();
        for (key, value) in data.entries() {
            body.push(format!("{}={}", key.clone(), value.clone()));
        }
        let body = body.join("&");
        self.set_header("Content-Type", self.content_type.clone().str());
        self.set_header("Content-Length", format!("{}", body.len()).as_str());
        self.body = Body::XWwwFormUrlencoded(body);
    }
    pub fn header(&mut self) -> String {
        let mut text = vec![];
        let uri = if self.query.is_empty() {
            format!("{}", self.path)
        } else {
            format!("{}?{}", self.path, urlencoding_encode(&*self.query))
        };
        text.push(format!("{} {} {}", self.method.str(), uri, self.version.str()));
        text.push(format!("Host: {}", self.domain.as_str()));
        for (key, value) in self.headers.iter() {
            text.push(format!("{}: {}", key, value));
        }
        text.push("".to_string());
        text.join("\r\n")
    }
    pub fn body(&mut self) -> Vec<u8> {
        let mut body = vec![];
        body.extend("\r\n".as_bytes().to_vec());
        if !self.body.bytes().is_empty() {
            body.extend(self.body.bytes());
        }
        body
    }
}

#[derive(Clone, Debug)]
pub enum Body {
    Json(JsonValue),
    Text(String),
    Xml(String),
    FormData(Vec<u8>),
    XWwwFormUrlencoded(String),
    None,
}

impl Body {
    pub fn default() -> Body {
        Self::None
    }
    pub fn bytes(&mut self) -> Vec<u8> {
        match self {
            Body::Json(e) => e.to_string().as_bytes().to_vec(),
            Body::Text(e) => e.clone().as_bytes().to_vec(),
            Body::Xml(e) => e.clone().as_bytes().to_vec(),
            Body::FormData(e) => e.to_vec().clone(),
            Body::XWwwFormUrlencoded(e) => e.clone().as_bytes().to_vec(),
            Body::None => "".as_bytes().to_vec()
        }
    }
}

#[derive(Clone, Debug)]
pub enum FormData {
    Text(String, String),
    File(String, String, String),
}

impl FormData {}