package com.yc.ship.module.trade.framework.common;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @author lishiqiang 906534176@qq.com
 * @version V1.0
 * &#064;Description: http
 * @date 2017-11-24
 * @Copyright: www.lishiqiang.cn
 */
public class HttpClient {

    private static final String USER_AGENT_VALUE = "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP)";

    private static final String JKS_CA_FILENAME = "tenpay_cacert.jks";

    private static final String JKS_CA_ALIAS = "tenpay";

    private static final String JKS_CA_PASSWORD = "";

    private static Logger LOG = LoggerFactory.getLogger(HttpClient.class);

    /**
     * ca证书文件
     */
    private File caFile;

    /**
     * 证书文件
     */
    private File certFile;

    /**
     * 证书密码
     */
    private String certPasswd;

    /**
     * 请求内容，无论post和get，都用get方式提供
     */
    private String reqContent;

    /**
     * 应答内容
     */
    private String resContent;

    /**
     * 请求方法
     */
    private String method;

    /**
     * 错误信息
     */
    private String errInfo;

    /**
     * 超时时间,以秒为单位
     */
    private int timeOut;

    /**
     * http应答编码
     */
    private int responseCode;

    /**
     * 字符编码
     */
    private String charset;

    private InputStream inputStream;

    public HttpClient() {
        this.caFile = null;
        this.certFile = null;
        this.certPasswd = "";

        this.reqContent = "";
        this.resContent = "";
        this.method = "POST";
        this.errInfo = "";
        //240秒
        this.timeOut = 240;

        this.responseCode = 0;
        this.charset = "UTF-8";

        this.inputStream = null;
    }

    public HttpClient(String url, String method, int timeOut, String charset) {
        this.caFile = null;
        this.certFile = null;
        this.certPasswd = "";

        this.reqContent = url;
        this.resContent = "";
        this.method = method;
        this.errInfo = "";
        //30秒
        this.timeOut = timeOut;

        this.responseCode = 0;
        this.charset = charset;

        this.inputStream = null;
    }

    public static String callHttpPost(String url) {
        // 默认超时时间60秒
        return callHttpPost(url, 240);
    }

    public static String callHttpPost(String url, int connect_timeout) {
        // 默认编码 UTF-8
        return callHttpPost(url, connect_timeout, "UTF-8");
    }

    public static String callHttpPost(String url, int connect_timeout, String encode) {
        HttpClient client = new HttpClient(url, "POST", connect_timeout, encode);
        client.call();
        return client.getResContent();
    }

    public static String callHttpsPost(String url) {

        HttpClient client = new HttpClient(url, "POST", 240, "UTF-8");
        client.calls();
        return client.getResContent();

    }

    /**
     * 设置证书信息
     *
     * @param certFile   证书文件
     * @param certPasswd 证书密码
     */
    public void setCertInfo(File certFile, String certPasswd) {
        this.certFile = certFile;
        this.certPasswd = certPasswd;
    }

    /**
     * 设置ca
     *
     * @param caFile
     */
    public void setCaInfo(File caFile) {
        this.caFile = caFile;
    }

    /**
     * 设置请求内容
     *
     * @param reqContent 表求内容
     */
    public void setReqContent(String reqContent) {
        this.reqContent = reqContent;
    }

    /**
     * 获取结果内容
     *
     * @return String
     * @throws IOException
     */
    public String getResContent() {
        try {
            this.doResponse();
        } catch (IOException e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
            //return "";
        }

        return this.resContent;
    }

    /**
     * 设置请求方法post或者get
     *
     * @param method 请求方法post/get
     */
    public void setMethod(String method) {
        this.method = method;
    }

    /**
     * 获取错误信息
     *
     * @return String
     */
    public String getErrInfo() {
        return this.errInfo;
    }

    /**
     * 设置超时时间,以秒为单位
     *
     * @param timeOut 超时时间,以秒为单位
     */
    public void setTimeOut(int timeOut) {
        this.timeOut = timeOut;
    }

    /**
     * 获取http状态码
     *
     * @return int
     */
    public int getResponseCode() {
        return this.responseCode;
    }

    /**
     * 执行http调用。true:成功 false:失败
     *
     * @return boolean
     */
    public boolean call() {
        boolean isRet = false;
        if (null == this.caFile && null == this.certFile) {
            try {
                this.callHttp();
                isRet = true;
            } catch (IOException e) {
                LOG.error("", e);
                this.errInfo = e.getMessage();
            } catch (Exception e) {
                LOG.error("", e);
                this.errInfo = e.getMessage();
            }
            return isRet;
        }
        return calls();
    }

    public boolean calls() {
        boolean isRet = false;
        try {
            this.callHttps();
            isRet = true;
        } catch (UnrecoverableKeyException e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
        } catch (KeyManagementException e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
        } catch (CertificateException e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
        } catch (KeyStoreException e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
        } catch (NoSuchAlgorithmException e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
        } catch (IOException e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
        } catch (Exception e) {
            LOG.error("", e);
            this.errInfo = e.getMessage();
        }
        return isRet;
    }

    protected void callHttp() throws IOException {
        if ("POST".equals(this.method.toUpperCase())) {
            String url = HttpClientUtil.getURL(this.reqContent);
            String queryString = HttpClientUtil.getQueryString(this.reqContent);
            byte[] postData = queryString.getBytes(this.charset);
            this.httpPostMethod(url, postData);
            return;
        }
        this.httpGetMethod(this.reqContent);
    }

    protected void callHttps() throws IOException, CertificateException,
            KeyStoreException, NoSuchAlgorithmException,
            UnrecoverableKeyException, KeyManagementException {
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, new TrustManager[]{new TrustAnyTrustManager()},
                new java.security.SecureRandom());
        if ("POST".equals(this.method.toUpperCase())) {
            String url = HttpClientUtil.getURL(this.reqContent);
            String queryString = HttpClientUtil.getQueryString(this.reqContent);
            byte[] postData = queryString.getBytes(this.charset);
            this.httpsPostMethod(url, postData, sslContext);
            return;
        }
        this.httpsGetMethod(this.reqContent, sslContext);
    }

    /**
     * 以http post方式通信
     *
     * @param url
     * @param postData
     * @throws IOException
     */
    protected void httpPostMethod(String url, byte[] postData) throws IOException {
        HttpURLConnection conn = HttpClientUtil.getHttpURLConnection(url);
        this.doPost(conn, postData);
    }

    /**
     * 以http get方式通信
     *
     * @param url
     * @throws IOException
     */
    protected void httpGetMethod(String url) throws IOException {
        HttpURLConnection httpConnection = HttpClientUtil.getHttpURLConnection(url);
        this.setHttpRequest(httpConnection);
        httpConnection.setRequestMethod("GET");
        this.responseCode = httpConnection.getResponseCode();
        this.inputStream = httpConnection.getInputStream();
    }

    /**
     * 以https get方式通信
     *
     * @param url
     * @param sslContext
     * @throws IOException
     */
    protected void httpsGetMethod(String url, SSLContext sslContext) throws IOException {
        SSLSocketFactory sf = sslContext.getSocketFactory();
        HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url);
        conn.setSSLSocketFactory(sf);
        this.doGet(conn);
    }

    protected void httpsPostMethod(String url, byte[] postData, SSLContext sslContext) throws IOException {
        SSLSocketFactory sf = sslContext.getSocketFactory();
        HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url);
        conn.setSSLSocketFactory(sf);
        this.doPost(conn, postData);
    }

    /**
     * 设置http请求默认属性
     *
     * @param httpConnection
     */
    protected void setHttpRequest(HttpURLConnection httpConnection) {
        //设置连接超时时间
        httpConnection.setConnectTimeout(this.timeOut * 1000);
        //User-Agent
        httpConnection.setRequestProperty("User-Agent", HttpClient.USER_AGENT_VALUE);
        //不使用缓存
        httpConnection.setUseCaches(false);
        //允许输入输出
        httpConnection.setDoInput(true);
        httpConnection.setDoOutput(true);
    }

    /**
     * 处理应答
     *
     * @throws IOException
     */
    protected void doResponse() throws IOException {
        if (null == this.inputStream) {
            return;
        }
        //获取应答内容
        this.resContent = HttpClientUtil.InputStreamTOString(this.inputStream, this.charset);
        //关闭输入流
        this.inputStream.close();
    }

    /**
     * post方式处理
     *
     * @param conn
     * @param postData
     * @throws IOException
     */
    protected void doPost(HttpURLConnection conn, byte[] postData) throws IOException {
        // 以post方式通信
        conn.setRequestMethod("POST");
        // 设置请求默认属性
        this.setHttpRequest(conn);
        // Content-Type
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
        final int len = 1024; // 1KB
        HttpClientUtil.doOutput(out, postData, len);
        // 关闭流
        out.close();
        // 获取响应返回状态码
        this.responseCode = conn.getResponseCode();
        // 获取应答输入流
        this.inputStream = conn.getInputStream();
    }

    /**
     * get方式处理
     *
     * @param conn
     * @throws IOException
     */
    protected void doGet(HttpURLConnection conn) throws IOException {
        //以GET方式通信
        conn.setRequestMethod("GET");
        //设置请求默认属性
        this.setHttpRequest(conn);
        //获取响应返回状态码
        this.responseCode = conn.getResponseCode();
        //获取应答输入流
        this.inputStream = conn.getInputStream();
    }

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

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

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

}
