package weaver.interfaces.htsc.wpscenter.utils;

import net.sf.json.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import weaver.hrm.User;
import weaver.interfaces.email.SSLClient;
import weaver.systeminfo.SystemEnv;
import weaver.workflow.logging.Logger;
import weaver.workflow.logging.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * 网络请求工具类
 */
public class HttpUtil {

    /**
     * 日志输出工具类
     */
    private Logger log = LoggerFactory.getLogger(HttpUtil.class);

    public static final String EMPTY_STRING_MD5 = "d41d8cd98f00b204e9800998ecf8427e";

    /**
     * 从服务器获取响应数据的超时时间
     */
    public static final int DEF_SOCKET_TIMEOUT = 5*1000;

    /**
     * 服务器连接超时时间
     */
    public static final int DEF_CONNECT_TIMEOUT = 3*1000;

    /**
     * 从连接池获取请求时间
     */
    public static final int DEF_CONNECTION_REQUEST_TIMEOUT = 10*1000;

    // 指定ak/sk
    private String ak;
    private String sk;

	// 持有用户
	private User user = null;

    public HttpUtil(User user) {
		this.user = user;
	}

    public User getUser() {
        return user;
    }

    public HttpUtil setUser(User user) {
        this.user = user;
        return this;
    }

    public Logger getLog() {
        return log;
    }

    public HttpUtil setLog(Logger log) {
        this.log = log;
        return this;
    }

    public String getAk() {
        return ak;
    }

    public HttpUtil setAk(String ak) {
        this.ak = ak;
        return this;
    }

    public String getSk() {
        return sk;
    }

    public HttpUtil setSk(String sk) {
        this.sk = sk;
        return this;
    }

    /**
     * POST的方式请求接口
     * 参数是JSON格式
     * @param url
     * @param requestContent
     * @param headers
     * @return
     * @throws Exception
     */
    public JSONObject post(String url, JSONObject requestContent, Map<String, String> headers) throws Exception {
        if(Config.isLogInfo()) {
            log.info("url:["  + url + "], requestContent = " + requestContent.toString());
        }
        HttpEntity requestEntity = new StringEntity(requestContent.toString(),ContentType.APPLICATION_JSON);
        return post(url, requestEntity, headers);
    }

    /**
     * POST的方式请求接口
     * 参数是字符串格式
     * @param url
     * @param requestContent
     * @param headers
     * @return
     * @throws Exception
     */
    public JSONObject post(String url, String requestContent, Map<String, String> headers) throws Exception {
        if(Config.isLogInfo()) {
            log.info("url:["  + url + "], requestContent = " + requestContent);
        }
        HttpEntity requestEntity = new StringEntity(requestContent.toString(),"UTF-8");
        return post(url, requestEntity, headers);
    }

	/**
	 * POST的方式请求接口
	 * @param url 请求的接口地址
	 * @param requestEntity 请求的参数实体
	 * @param headers 请求头
	 * @return
	 * @throws Exception
	 */
    public JSONObject post(String url, HttpEntity requestEntity, Map<String, String> headers) throws Exception {
	    JSONObject response = new JSONObject();
        if(Config.isLogInfo()) {
            log.info("url:["  + url + "], headers = " + (null == headers ? "" :headers.toString()));
        }
	    HttpPost post = new HttpPost(url);
		post.setEntity(requestEntity);

        //设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(Config.getPropIntValue("doccenter_socket_timeout",DEF_SOCKET_TIMEOUT))
                .setConnectTimeout(Config.getPropIntValue("doccenter_connect_timeout",DEF_CONNECT_TIMEOUT))
                .setConnectionRequestTimeout(Config.getPropIntValue("doccenter_connection_request_timeout",DEF_CONNECTION_REQUEST_TIMEOUT))
                .build();

        post.setConfig(requestConfig);

		if(null != headers && !headers.isEmpty()) {
			// headers.keySet().forEach((key) -> { post.addHeader(key, headers.get(key)); });
			// 修改为兼容低版本jdk的写法
            Iterator<String> iterator = headers.keySet().iterator();
            while(iterator.hasNext()){
                String key = iterator.next();
                post.addHeader(key, headers.get(key));
            }
		}

		DefaultHttpClient client = null;
		client = url.startsWith("https:") ? new SSLClient() : new DefaultHttpClient();

        // 设置签名信息
        WPS3Sign(post);

		HttpResponse res = client.execute(post);

        return parseResponse(res);
    }

    /**
     * Get方式请求, 获取JSON数据
     * @param url
     * @return
     * @throws Exception
     */
    public JSONObject get(String url, Map<String, String> headers) throws Exception {
        HttpResponse response = getResponse(url, headers);
        return parseResponse(response);
    }

	/**
	 * Get方式请求
	 * @param url
	 * @return
	 * @throws Exception
	 */
	private HttpResponse getResponse(String url, Map<String, String> headers) throws Exception {
        if(null == url || url.isEmpty()){
            // 地址有误
            throw new IllegalArgumentException(SystemEnv.getHtmlLabelName(83410, Tools.getUserLanguageid(user)));
        }

        DefaultHttpClient client = new DefaultHttpClient();
        HttpGet get = new HttpGet(url);

        //设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(Config.getPropIntValue("doccenter_socket_timeout",DEF_SOCKET_TIMEOUT))
                .setConnectTimeout(Config.getPropIntValue("doccenter_connect_timeout",DEF_CONNECT_TIMEOUT))
                .setConnectionRequestTimeout(Config.getPropIntValue("doccenter_connection_request_timeout",DEF_CONNECTION_REQUEST_TIMEOUT))
                .build();

        get.setConfig(requestConfig);

        if(null != headers && !headers.isEmpty()){
            // headers.keySet().forEach((key) -> { get.addHeader(key, headers.get(key)); });
            // 修改为兼容低版本jdk的写法
            Iterator<String> iterator = headers.keySet().iterator();
            while(iterator.hasNext()){
                String key = iterator.next();
                get.addHeader(key, headers.get(key));
            }
        }

        // 根据是否是https协议，请求不通的Client
        if(url.startsWith("https:")){
            client = new SSLClient();
        }else{
            client = new DefaultHttpClient();
        }

        WPS3Sign(get);

        // 解析获取获取到的结果值
        HttpResponse response = client.execute(get);

        return response;
	}

    /**
     * 解析请求接口返回的结果
     * @param response
     * @return
     * @throws Exception
     */
    private JSONObject parseResponse(HttpResponse response) throws Exception {
        JSONObject result = new JSONObject();
        int code = response.getStatusLine().getStatusCode();

        if(code == HttpStatus.SC_OK){
            HttpEntity entity = response.getEntity();
            String responseData = EntityUtils.toString(entity);// 返回json格式：
            result = JSONObject.fromObject(responseData);
            if(!result.containsKey("code")) {
                result.put("code", "0");
            }
        }else{
            if(Config.isLogInfo()) {
                log.info("code:" + code + ",StatusLine:" +response.getStatusLine());
            }
            result.put("httpcode", code);
            result.put("httmsg", response.getStatusLine());
            String responseBody = IOUtils.toString(response.getEntity().getContent());
            if(Config.isLogInfo()) {
                log.info("reponse body:" + responseBody);
            }

            JSONObject responseJson = JSONObject.fromObject(responseBody);
            if(responseJson.containsKey("result")) {
                result.put("code", Tools.getJsonData(responseJson, "result"));
            } else {
                result.put("code", code);
            }

            if(responseJson.containsKey("msg")) {
                result.put("msg", Tools.getJsonData(responseJson, "msg"));
            } else {
                result.put("msg", response.getStatusLine());
            }

            // 状态异常，想上抛出
            // throw new RuntimeException(SystemEnv.getHtmlLabelName(10004206, Tools.getUserLanguageid(user)) + code);
        }
        if(Config.isLogInfo()) {
            log.info("http reponse:" + result.toString());
        }
        return result;
    }

    /**
     * 下载文件，生成附件
     * @param url
     * @param comefrom
     * @return
     * @throws Exception
     */
    public int getFileFromRomote(String url, String filename, String comefrom) {
        if(Config.isLogInfo()) {
            log.info("url:["  + url + "], filename:[" + filename + "], comefrom:[" + comefrom + "]");
        }
        try {
            Tools tools = new Tools();
            return tools.saveToImageFile(getUrlImputStream(url), filename, comefrom);
        } catch (Exception e) {
            log.error(e);
        }
        return -2;
    }

    public InputStream getUrlImputStream(String urlStr) throws Exception {
        InputStream in = null;

        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //设置超时间为3秒
        conn.setConnectTimeout(Config.getPropIntValue("doccenter_connect_timeout",DEF_CONNECT_TIMEOUT));

        //防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

        //得到输入流
        return conn.getInputStream();
    }

    public int getFileFromRomoteForWPSDoccenter(String url, String filename, String comefrom) throws Exception {
        if(Config.isLogInfo()) {
            log.info("url:["  + url + "], filename:[" + filename + "], comefrom:[" + comefrom + "]");
        }

        Tools tools = new Tools();
        return tools.saveToImageFile(getUrlImputStreamForWPSDoccenter(url), filename, comefrom);
    }

    public InputStream getUrlImputStreamForWPSDoccenter(String urlStr) throws Exception {
        InputStream in = null;

        TokenUtil tokenUtil = new TokenUtil();
        String appToken = tokenUtil.getFileFormatToken(user);
        urlStr = urlStr + (urlStr.contains("?") ? "&" : "?") + "app_token=" + appToken;

        Map<String, String> headers = new HashMap<String, String>();
        // headers.put("User-Agent","Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
        HttpResponse response = getResponse(urlStr, headers);
        HttpEntity entity = response.getEntity();
        int code = response.getStatusLine().getStatusCode();

        if(code != HttpStatus.SC_OK){
            String responseBody = IOUtils.toString(response.getEntity().getContent());
            log.warn("download file reponse body:" + responseBody);
            throw new IllegalStateException(code + " " + response.getStatusLine().getReasonPhrase());
        }

        //得到输入流
        return entity.getContent();
    }

    public void addToMultipartEntity(MultipartEntity mEntity, Map<String,Object> map) throws UnsupportedEncodingException {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            mEntity.addPart(entry.getKey(),
                    new StringBody(String.valueOf(entry.getValue()), ContentType.MULTIPART_FORM_DATA));
        }
        return ;
    }

    public MultipartEntity createMultipartFormEntity(Map<String,Object> map) throws UnsupportedEncodingException {
        MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, Charset.forName("UTF-8"));
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            multipartEntity.addPart(entry.getKey(),
                    new StringBody(String.valueOf(entry.getValue()), Charset.forName("UTF-8")));
        }
        return multipartEntity;
    }

    public HttpEntity getMultipartFormEntity(Map<String,Object> map) throws UnsupportedEncodingException {
        MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            multipartEntity.addPart(entry.getKey(),
                    new StringBody(String.valueOf(entry.getValue()), ContentType.MULTIPART_FORM_DATA));
        }
        return multipartEntity.build();
    }

    public HttpEntity getFormEntity(Map<String,Object> map){
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            formparams.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
        }
        return new UrlEncodedFormEntity((Iterable<? extends NameValuePair>) formparams, Consts.UTF_8);
    }

    public HttpEntity getJsonEntity(Map<String,Object> map){
        com.alibaba.fastjson.JSONObject jsonParam = new com.alibaba.fastjson.JSONObject();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            jsonParam.put(entry.getKey(),entry.getValue());
        }
        return new StringEntity(jsonParam.toJSONString(), ContentType.APPLICATION_JSON);
    }

    public void WPS3Sign(HttpEntityEnclosingRequestBase request){
        String contentType = ContentType.APPLICATION_JSON.toString();

        byte[] contentBytes = new byte[0];
        try {
            contentBytes = IOUtils.toByteArray(request.getEntity().getContent());
        } catch (IOException e) {
            log.error(e);
        }

        // 正文内容解析获取md5
        String contentMd5 = (null != contentBytes && contentBytes.length > 0) ? DigestUtils.md5Hex(contentBytes) : "";

        WPS3Sign(request, contentMd5);
    }

    /**
     * GET 请求使用
     * @param request
     */
    public void WPS3Sign(HttpRequestBase request){
        WPS3Sign(request, EMPTY_STRING_MD5);
    }

    public void WPS3Sign(HttpRequestBase request, String contentMd5){
        String contentType = "application/json";

        String path = request.getURI().getPath();
        String query = request.getURI().getQuery();

        if (path.startsWith("/kubewps/open")) {
            path = path.replace("/kubewps/open", "");
        }

        String url = path;
        if (null != query && !query.isEmpty()) {
            url = url + "?" + query;
        }

        String appId = Config.getWpsDocCenterAppid();
        String sercet = Config.getWpsDocCenterSercet();

        // 如果指定了aksk，则使用指定的
        if(!Tools.isEmptyOrNull(getAk()) && !Tools.isEmptyOrNull(getSk())) {
            appId = getAk();
            sercet = getSk();
        }

        DateFormatUtil dateFormatUtil = new DateFormatUtil();
        String dateFormated = dateFormatUtil.getNowDate();

        // "WPS-3:" + AppId + ":" + sha1(AppKey + Content-Md5 + URL + Content-Type + Date)
        log.info("WPS3Sign sha1str:" + sercet + contentMd5 + url + contentType + dateFormated);
        String authorizationSha1 = getSha1(sercet + contentMd5 + url + contentType + dateFormated);

        log.info("WPS3Sign Content-Type:" + contentType);
        log.info("WPS3Sign Content-Md5:" + contentMd5);
        log.info("WPS3Sign Date:" + dateFormated);
        log.info("WPS3Sign X-Auth:" + String.format("WPS-3:%s:%s", appId, authorizationSha1));
        request.addHeader("Content-Type", contentType);
        request.addHeader("Content-Md5", contentMd5);
        request.addHeader("Date", dateFormated);
        request.addHeader("X-Auth", String.format("WPS-3:%s:%s", appId, authorizationSha1));
    }

    public static String getSha1(String str) {
        // 获取指定摘要算法的messageDigest对象
        MessageDigest messageDigest = null; // 此处的sha代表sha1
        try {
            messageDigest = MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 调用digest方法，进行加密操作
        byte[] cipherBytes = messageDigest.digest(str.getBytes());
        return toHexString4Sha1(cipherBytes);
    }

    /**
     * 字节数组转字符串
     *
     * @param bytes
     * @return
     */
    public static String toHexString4Sha1(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}
