use std::fs;
use std::path::Path;

use chrono::{Utc};
use json::JsonValue;
use crate::config::Config;

/// 响应
#[derive(Clone, Debug)]
pub struct Response {
    config: Config,
    /// 版本号
    version: String,
    code: usize,
    /// 响应正文类型
    content_type: String,
    /// 正文使用的编码
    content_charset: String,
    response: Vec<String>,
}

impl Response {
    pub fn new(config: Config, version: String) -> Response {
        Self {
            config,
            version,
            code: 0,
            content_type: "text/plain".to_string(),
            content_charset: "UTF-8".to_string(),
            response: vec![],
        }
    }
    pub fn set_code(&mut self, code: usize) -> &mut Self {
        self.response = vec![];
        self.code = code;
        let msg = match code {
            100 => "Continue",
            101 => "Switching Protocols",
            102 => "Processing",
            200 => "OK",
            201 => "Created",
            301 => "Permanently Moved",// 重定向
            302 => "Move temporarily",
            403 => "Forbidden",
            404 => "Not Found",//服务器无法根据客户端的请求找到资源（网页）。通过此代码，网站设计人员可设置"您所请求的资源无法找到"的个性页面
            500 => "Internal Server Error",//服务器内部错误，无法完成请求
            501 => "Not Implemented",//服务器不支持请求的功能，无法完成请求
            502 => "Bad Gateway",//作为网关或者代理工作的服务器尝试执行请求时，从远程服务器接收到了一个无效的响应
            503 => "Service Unavailable",//由于超载或系统维护，服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
            504 => "Gateway Time-out",//充当网关或代理的服务器，未及时从远端服务器获取请求
            505 => "HTTP Version Not Supported",//服务器不支持请求的HTTP协议的版本，无法完成处理
            _ => {
                self.code = 505;
                "HTTP Version Not Supported"
            }
        };
        self.response.push(format!("{} {} {}", self.version, self.code, msg));
        self.response.push(format!("Date: {}", Utc::now().format("%a, %d %b %Y %H:%M:%S GMT").to_string()));
        self.response.push(format!("Server: Blue Rain Rust"));
        self
    }
    pub fn set_content_type(&mut self, content_type: &str) -> &mut Self {
        self.content_type = content_type.to_string();
        self.set_code(200);
        match content_type {
            "json" => {
                self.response.push(format!("Connection: keep-alive"));
                self.response.push(format!("Cache-Control: no-cache,max-age=0"));
                self.response.push(format!("Content-type: application/json;charset={}", self.content_charset))
            }
            "html" => {
                self.response.push(format!("Connection: keep-alive"));
                self.response.push(format!("Access-Control-Max-Age: {}", self.config.cors.max_age));
                self.response.push(format!("Content-type: text/html;charset=utf-8"))
            }
            "url" => {
                self.set_code(301);
                self.response.push(format!("Connection: Close"));
                self.response.push(format!("Cache-control: no-cache"));
            }
            "download" => {
                self.response.push(format!("Connection: close"));
                self.response.push(format!("Cache-Control: no-cache,max-age=0"));
                self.response.push(format!("Content-type: application/octet-stream"));
                self.response.push(format!("Access-Control-Expose-Headers: {}", self.config.cors.expose_headers));
            }
            _ => {
                self.response.push(format!("Connection: keep-alive"));
                self.response.push(format!("Cache-Control: no-cache,max-age=0"));
                self.response.push(format!("Content-type: text/html;charset=utf-8"))
            }
        }
        self
    }


    pub fn set_connection(&mut self) -> &mut Self {
        self.response.push(format!("Connection: keep-alive"));
        self
    }
    pub fn set_access_control_allow_origin(&mut self) -> &mut Self {
        self.response.push(format!("Access-Control-Allow-Origin: {}", "*"));
        self
    }
    pub fn set_cache_control(&mut self, max_age: usize) -> &mut Self {
        self.response.push(format!("Cache-Control: no-cache,max-age={}", max_age));
        self
    }
    fn set_access_control_allow_credentials(&mut self) -> &mut Self {
        if self.config.cors.allow_credentials {
            self.response.push(format!("Access-Control-Allow-Credentials: {}", self.config.cors.allow_credentials));
        }
        self
    }
    /// options 响应
    pub fn options(&mut self) -> String {
        self.set_code(200);
        self.set_connection();
        self.set_access_control_allow_origin();
        self.set_access_control_allow_credentials();
        self.response.push(format!("Access-Control-Allow-Methods: {}", self.config.cors.allow_methods));
        self.response.push(format!("Access-Control-Allow-Headers: {}", self.config.cors.allow_headers));
        self.response.push(format!("Access-Control-Expose-Headers: {}", self.config.cors.expose_headers));
        self.set_cache_control(1800);
        self.response.push(format!("Content-type: text/html;charset=utf-8"));
        self.response.push(format!("Content-Length: 0\r\n"));
        self.response.push(format!("{}", ""));
        self.response.join("\r\n")
    }
    /// 读取文件返回
    pub fn file(&mut self, filename: String) -> String {
        let sufxx: Vec<&str> = filename.split(".").collect();
        let sufxx = sufxx[sufxx.len() - 1];
        let file = fs::read(filename.as_str()).unwrap();
        let contents = unsafe { String::from_utf8_unchecked(file) };
        let content_type = match sufxx {
            "jpg" => "image/jpg",
            "png" => "image/png",
            "bmp" => "image/bmp",
            "jpeg" => "image/jpeg",
            "svg" => "image/svg+xml",
            "webp" => "image/webp",
            "ico" => "image/ico",
            "gif" => "image/gif",
            "avif" => "image/avif",
            "pdf" => "application/pdf",
            "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "xls" => "application/vnd.ms-excel",
            "xml" => "text/xml",
            "json" => "application/json",
            "html" => "text/html;charset=utf-8",
            _ => "text/plain;charset=utf-8"
        };
        self.set_code(200);
        self.response.push(format!("Content-Type: {}", content_type));
        self.response.push(format!("Cache-Control: private,max-age=0"));
        self.response.push(format!("Strict-Transport-Security: max-age=0; includeSubDomains;"));
        self.response.push(format!("ETag: {}", br_crypto::hash::str_to_md5(&*contents.to_string())));
        self.response.push(format!("Content-Length: {}\r\n", contents.len()));
        self.response.push(format!("{}", contents));
        self.response.join("\r\n")
    }
    pub fn receipt(&mut self, content: JsonValue) -> String {
        self.set_access_control_allow_origin();
        self.response.push(format!("Access-Control-Allow-Methods: {}", self.config.cors.allow_methods));
        self.response.push(format!("Access-Control-Allow-Headers: {}", self.config.cors.allow_headers));
        self.response.push(format!("Access-Control-Expose-Headers: {}", self.config.cors.expose_headers));
        match self.content_type.as_str() {
            "json" => {
                self.response.push(format!("Content-Length: {}", content.to_string().len()));
                if content.len() > 0 {
                    self.response.push(format!("\r\n{}", content.to_string()));
                }
            }
            "html" => {
                self.response.push(format!("Connection: keep-alive"));
                self.response.push(format!("Access-Control-Max-Age: {}", self.config.cors.max_age));
                self.response.push(format!("Content-type: text/html;charset=utf-8"));
            }
            "url" => {
                self.response.push(format!("Location: {}", content.to_string()));
                self.response.push(format!("\r\n{}", "".to_string()));
            }
            "download" => {
                let path = Path::new(content.as_str().unwrap());
                let filename = path.file_name().unwrap();
                let filename = br_crypto::encoding::urlencoding_encode(filename.to_str().unwrap());
                self.response.push(format!("Content-Disposition: attachment; filename={}", filename));
                let file = fs::read(path.to_str().unwrap()).unwrap();
                let content = unsafe { String::from_utf8_unchecked(file.clone()) };
                self.response.push(format!("Content-Length: {}\r\n", file.len()));
                self.response.push(content);
            }
            _ => {
                self.set_access_control_allow_origin();
                self.response.push(format!("Connection: keep-alive"));
                self.response.push(format!("Cache-Control: no-cache,max-age=0"));
                self.response.push(format!("Content-type: text/html;charset=utf-8"));
            }
        }

        self.response.join("\r\n")
    }
}