package com.dgtly.wxportal.utils.ESign;

import com.alibaba.fastjson.JSONObject;
import com.dgtly.common.exception.BusinessException;
import com.dgtly.wxportal.config.ESignConfig;
import com.dgtly.wxportal.exception.ESignException;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

@Component
public class ESignHttpUtil {
    private static final Logger log = LoggerFactory.getLogger(ESignHttpUtil.class);


    @Autowired
    private ESignConfig eSignConfig;

    /**
     * 根据E签宝的大部分返回值实体简单处理结果增加异常判断
     * @param eurl
     * @param param
     * @param querys
     * @return
     */
    public JSONObject doPostGetJson(ESignUrl eurl, JSONObject param,String ...querys){
        String url = eSignConfig.getUrl(eurl,querys);
        log.info("开始调用E请求地址:{}", url);
        String str = doPost(url,param.toJSONString());
        log.info("调用E请求地址返回结果:{}", str);
        JSONObject json =JSONObject.parseObject(str);
        int code = json.getInteger("code");
        if(code==30500156) {
            return null;
        }else {
            if (code != 0) {
                throw new ESignException(code, url, json.getString("message"));
            }
            return json;
        }
    }

    /**
     * 根据E签宝的大部分返回值实体简单处理结果增加异常判断
     * @param eurl
     * @param param
     * @param querys
     * @return
     */
    public JSONObject doGetGetJson(ESignUrl eurl, JSONObject param,String ...querys){
        String url = eSignConfig.getUrl(eurl,querys);
        String str = doGet(url);
//        String str = doGet(url,param.toJSONString());
        JSONObject json =JSONObject.parseObject(str);
        int code = json.getInteger("code");
        if (code==53000001){
          return null;
        }else{
            if (code != 0) {
                throw new ESignException(code, url, json.getString("message"));
            }
            return json;
        }
    }

    /**
     * 根据E签宝的大部分返回值实体简单处理结果增加异常判断
     * @param eurl
     * @param param
     * @param querys
     * @return
     */
    public JSONObject doPutGetJson(ESignUrl eurl, JSONObject param,String ...querys){
        String url = eSignConfig.getUrl(eurl,querys);
        String str = doPut(url,param.toJSONString());
        JSONObject json =JSONObject.parseObject(str);
        int code = json.getInteger("code");
        if(code!=0){
            throw new ESignException(code,url,json.getString("message"));
        }
        return json;
    }

    public String doPost(ESignUrl eurl, JSONObject param,String ...querys){
        String url = eSignConfig.getUrl(eurl,querys);
        return doPost(url,param.toJSONString());
    }


    /**
     * 向指定 URL 发送POST方法的请求并添加E签宝所需的请求头
     *
     * @param url 发送请求的 URL
     * @param json 请求参数，
     * @return 所代表远程资源的响应结果
     */
    private String doPost(String url , String json)
    {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try
        {

            log.info("sendPost - {}", url);
            // 打开和URL之间的连接
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sc.getSocketFactory();

            java.net.URL realUrl = new URL(url);

            HttpsURLConnection conn = (HttpsURLConnection) realUrl.openConnection();

            conn.setSSLSocketFactory(ssf);

            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("X-Tsign-Open-App-Id",eSignConfig.getAppId());
            conn.setRequestProperty("X-Tsign-Open-Token",eSignConfig.getAccessToken());
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            conn.setUseCaches(false);//设置不要缓存
            conn.setDoOutput(true);
            conn.setDoInput(true);
            String line;

            try{
                out = new PrintWriter(conn.getOutputStream());
                out.write(json);
                out.flush();
                in = new BufferedReader( new InputStreamReader(conn.getInputStream()));

                while ((line = in.readLine()) != null)
                {
                    result.append(line);
                }
            } catch (IOException e){
                if(conn.getResponseCode()==401){
                    log.error("请求E签宝接口报错401，token超时");
                    eSignConfig.reSetToken();
                }
                throw e;
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用ESignHttpUtil.doPost ConnectException, url=" + url + ",param_body=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost ConnectException, url=" + url + ",param=" + json );
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用ESignHttpUtil.doPost SocketTimeoutException, url=" + url + ",param=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost SocketTimeoutException, url=" + url + ",param=" + json );
        }
        catch (IOException e)
        {
            log.error("调用ESignHttpUtil.doPost IOException, url=" + url + ",param=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost IOException, url=" + url + ",param=" + json );
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.doPost Exception, url=" + url + ",param=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost Exception, url=" + url + ",param=" + json );
        }
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                log.error("调用in.close Exception, url=" + url + ",param=" + json, ex);
            }
        }
        return result.toString();
    }

    /**
     * 向指定 URL 发送PUT方法的请求并添加E签宝所需的请求头
     *
     * @param url 发送请求的 URL
     * @param json 请求参数，
     * @return 所代表远程资源的响应结果
     */
    private String doPut(String url , String json)
    {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try
        {

            log.info("sendPost - {}", url);
            // 打开和URL之间的连接
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sc.getSocketFactory();

            java.net.URL realUrl = new URL(url);

            HttpsURLConnection conn = (HttpsURLConnection) realUrl.openConnection();

            conn.setSSLSocketFactory(ssf);
            conn.setRequestMethod("PUT");
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("X-Tsign-Open-App-Id",eSignConfig.getAppId());
            conn.setRequestProperty("X-Tsign-Open-Token",eSignConfig.getAccessToken());
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            conn.setUseCaches(false);//设置不要缓存
            conn.setDoOutput(true);
            conn.setDoInput(true);
            String line;
            try{
                out = new PrintWriter(conn.getOutputStream());
                out.write(json);
                out.flush();
                in = new BufferedReader( new InputStreamReader(conn.getInputStream()));

                while ((line = in.readLine()) != null)
                {
                    result.append(line);
                }
            } catch (IOException e){
                if(conn.getResponseCode()==401){
                    log.error("请求E签宝接口报错401，token超时");
                    eSignConfig.reSetToken();
                }
                throw e;
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用ESignHttpUtil.doPost ConnectException, url=" + url + ",param_body=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost ConnectException, url=" + url + ",param=" + json );
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用ESignHttpUtil.doPost SocketTimeoutException, url=" + url + ",param=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost SocketTimeoutException, url=" + url + ",param=" + json );
        }
        catch (IOException e)
        {
            log.error("调用ESignHttpUtil.doPost IOException, url=" + url + ",param=" + json, e);

            throw new BusinessException("调用ESignHttpUtil.sendJsonPost IOException, url=" + url + ",param=" + json );
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.doPost Exception, url=" + url + ",param=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost Exception, url=" + url + ",param=" + json );
        }
        finally
        {

            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                log.error("调用in.close Exception, url=" + url + ",param=" + json, ex);
            }
        }
        return result.toString();
    }

    public String doDelete(String url , String json)
    {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try
        {

            log.info("sendPost - {}", url);
            // 打开和URL之间的连接
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sc.getSocketFactory();

            java.net.URL realUrl = new URL(url);

            HttpsURLConnection conn = (HttpsURLConnection) realUrl.openConnection();

            conn.setSSLSocketFactory(ssf);
            conn.setRequestMethod("DELETE");
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("X-Tsign-Open-App-Id",eSignConfig.getAppId());
            conn.setRequestProperty("X-Tsign-Open-Token",eSignConfig.getAccessToken());
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            conn.setUseCaches(false);//设置不要缓存
            conn.setDoOutput(true);
            conn.setDoInput(true);
            String line;
            try{
                out = new PrintWriter(conn.getOutputStream());
                out.write(json);
                out.flush();
                in = new BufferedReader( new InputStreamReader(conn.getInputStream()));

                while ((line = in.readLine()) != null)
                {
                    result.append(line);
                }
            } catch (IOException e){
                if(conn.getResponseCode()==401){
                    log.error("请求E签宝接口报错401，token超时");
                    eSignConfig.reSetToken();
                }
                throw e;
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用ESignHttpUtil.doPost ConnectException, url=" + url + ",param_body=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost ConnectException, url=" + url + ",param=" + json );
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用ESignHttpUtil.doPost SocketTimeoutException, url=" + url + ",param=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost SocketTimeoutException, url=" + url + ",param=" + json );
        }
        catch (IOException e)
        {
            log.error("调用ESignHttpUtil.doPost IOException, url=" + url + ",param=" + json, e);

            throw new BusinessException("调用ESignHttpUtil.sendJsonPost IOException, url=" + url + ",param=" + json );
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.doPost Exception, url=" + url + ",param=" + json, e);
            throw new BusinessException("调用ESignHttpUtil.sendJsonPost Exception, url=" + url + ",param=" + json );
        }
        finally
        {

            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                log.error("调用in.close Exception, url=" + url + ",param=" + json, ex);
            }
        }
        return result.toString();
    }

    private String doGet(String url, String json)
    {
        PrintWriter out = null;
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try
        {
            String urlNameString = url;
            log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);

            HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("X-Tsign-Open-App-Id",eSignConfig.getAppId());
            connection.setRequestProperty("X-Tsign-Open-Token",eSignConfig.getAccessToken());
            connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.connect();

            String line;

            try{
                if(json!=null){
                    out = new PrintWriter(connection.getOutputStream());
                    out.write(json);
                    out.flush();
                }

                in = new BufferedReader( new InputStreamReader(connection.getInputStream()));

                while ((line = in.readLine()) != null)
                {
                    result.append(line);
                }
            } catch (IOException e){
                if(connection.getResponseCode()==401){
                    log.error("请求E签宝接口报错401，token超时");
                    eSignConfig.reSetToken();
                }
                throw e;
            }
            log.info("recv - {}", result);
        }
        catch(ConnectException e)
        {
            log.error("调用ESignHttpUtil.sendGet ConnectException, url=" + url , e);
            throw new BusinessException("调用ESignHttpUtil.sendGet ConnectException, url=" + url );
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用ESignHttpUtil.sendGet SocketTimeoutException, url=" + url , e);
            throw new BusinessException("调用ESignHttpUtil.sendGet SocketTimeoutException, url=" + url );
        }
        catch (IOException e)
        {
            log.error("调用ESignHttpUtil.sendGet IOException, url=" + url, e);
            throw new BusinessException("调用ESignHttpUtil.sendGet IOException, url=" + url );
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url , e);
            throw new BusinessException("调用ESignHttpUtil.sendGet Exception, url=" + url );
        }
        finally
        {

            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (Exception ex)
            {
                log.error("调用in.close Exception, url=" + url , ex);
            }
        }
        return result.toString();
    }

    private String doGet(String url)
    {
        return doGet(url,null);
    }

    private static class TrustAnyTrustManager implements X509TrustManager
    {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
        {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
        {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers()
        {
            return new X509Certificate[] {};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier
    {
        @Override
        public boolean verify(String hostname, SSLSession session)
        {
            return true;
        }
    }





    /**
     * 向E签宝指定 URL 上传文件
     *
     * @param url 发送请求的 URL
     * @param filePath 文件路径
     * @return 所代表远程资源的响应结果
     */
    public String upLoadFile(String url , String filePath ,String contentMD5,String contentType,int fileLength)
    {


        OutputStream out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try
        {

            byte[] fileBytes = FileUtils.readFileToByteArray(new File(filePath));
            log.info("sendPost - {}", url);
            // 打开和URL之间的连接
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new SecureRandom());

            //创建连接
            java.net.URL realUrl = new URL(url);
            HttpsURLConnection conn = (HttpsURLConnection) realUrl.openConnection();
            conn.setRequestMethod("PUT");
            //设置ssl
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sc.getSocketFactory();
            conn.setSSLSocketFactory(ssf);



            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            //设置请求头
            conn.setRequestProperty("Content-Type",contentType);
            conn.setRequestProperty("Content-MD5",contentMD5);
            conn.setRequestProperty("Content-Length",fileLength+"");

            conn.setUseCaches(false);//设置不要缓存
            conn.setDoOutput(true);
            conn.setDoInput(true);

            //写入请求体
            out = conn.getOutputStream();
            out.write(fileBytes);
            out.flush();
            in = new BufferedReader( new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null)
            {
                result.append(line);
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用ESignHttpUtil.upLoadFile ConnectException, url=" + url + ",filepath=" + filePath, e);
            throw new BusinessException("调用ESignHttpUtil.upLoadFile ConnectException, url=" + url);
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用ESignHttpUtil.upLoadFile ConnectException, url=" + url + ",filepath=" + filePath, e);
            throw new BusinessException("调用ESignHttpUtil.upLoadFile SocketTimeoutException, url=" + url );
        }
        catch (IOException e)
        {
            log.error("调用ESignHttpUtil.upLoadFile ConnectException, url=" + url + ",filepath=" + filePath, e);
            throw new BusinessException("调用ESignHttpUtil.upLoadFile IOException, url=" + url );
        }
        catch (Exception e)
        {
            log.error("调用ESignHttpUtil.upLoadFile ConnectException, url=" + url + ",filepath=" + filePath, e);
            throw new BusinessException("调用ESignHttpUtil.upLoadFile Exception, url=" + url );
        }
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                log.error("调用in.close Exception, url=" + url, ex);
            }
        }
        return result.toString();
    }


}
