package com.yn.bftl.thirdparty.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yn.bftl.common.common.exception.YnceError;
import com.yn.bftl.thirdparty.common.exception.YnceErrorException;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.*;
import java.io.*;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Map;

/**
 * http对应请求
 * 之前编写的HttpRequestUtil局限太大，重新成ByxHttpClientUtil
 *
 * @author huangzhongming
 * @create 2024-08-26
 */
public class ByxHttpClientUtil<T> {
    /**
     * 创建静态私有的变量保存该类对象
     */
    static private ByxHttpClientUtil instance;

    static private HttpHeaders headers;

    static private RestTemplate restTemplate;

    /** 签名算法 */
    private static String SIGN_ALG;

    private static PublicKey publicKey = null;

    public static ByxHttpClientUtil getInstance() {
        //判断instance是否是Uni的对象
        //没有则创建
        if (instance == null) {
            instance = new ByxHttpClientUtil();
        }
        if (headers == null) {
            headers = new HttpHeaders();
        } else {
            headers.clear();
        }
        if (restTemplate == null) {
            // 配置restTemplate
            HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
            httpRequestFactory.setConnectionRequestTimeout(3000);
            httpRequestFactory.setConnectTimeout(3000);
            httpRequestFactory.setReadTimeout(30000);
            restTemplate = new RestTemplate(httpRequestFactory);
        }
        // 默认为application/json
        headers.setContentType(MediaType.APPLICATION_JSON);
        return instance;
    }

    /**
     * 工厂模式
     */
    public static ByxHttpClientUtil getInstance(String signAlg, PublicKey pk) {
        //判断instance是否是Uni的对象
        //没有则创建
        if (instance == null) {
            instance = new ByxHttpClientUtil();
        }
        if (headers == null) {
            headers = new HttpHeaders();
        } else {
            headers.clear();
        }
        if (restTemplate == null) {
            // 配置restTemplate
            HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
            httpRequestFactory.setConnectionRequestTimeout(3000);
            httpRequestFactory.setConnectTimeout(3000);
            httpRequestFactory.setReadTimeout(30000);
            restTemplate = new RestTemplate(httpRequestFactory);
        }
        // 默认为application/json
        headers.setContentType(MediaType.APPLICATION_JSON);
        SIGN_ALG = signAlg;
        publicKey = pk;
        return instance;
    }

    public ByxHttpClientUtil setContentType(MediaType mediaType) {
        headers.setContentType(mediaType);
        return instance;
    }

    public ByxHttpClientUtil setHeaderMap(Map<String, String> headerMap) {
        if (headerMap.size() != 0) {
            for (Map.Entry<String, String> stringStringEntry : headerMap.entrySet()) {
                headers.add(stringStringEntry.getKey(), stringStringEntry.getValue());
            }
        }
        return instance;
    }

    /**
     * restTemplate-GET请求
     *
     * @param url          请求路径
     * @param urlParamsMap URL参数集合
     * @return JSONObject
     * @author huabiao
     * @create 2023/5/30  17:20
     */
    public JSONObject sendGet(String url, Map<String, Object> urlParamsMap) {
        // 处理URL请求参数
        String requestUrl = jointUrlParams(url, urlParamsMap);
        ResponseEntity<JSONObject> resp = restTemplate.getForEntity(requestUrl, JSONObject.class);

        if (resp.getStatusCodeValue() != 200) {
            throw new YnceErrorException(YnceError.YNCE_000000);
        }
        JSONObject body = resp.getBody();
        if (body == null) {
            throw new YnceErrorException(YnceError.YNCE_100002);
        }

        return body;
    }

    private void disableSslVerification() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }
            };
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * restTemplate-POST请求
     *
     * @param url         请求路径
     * @param requestJson 请求参数
     * @return JSONObject
     * @author huabiao
     * @create 2023/5/30  17:20
     */
    public JSONObject sendPost(String url, String requestJson) {
        // 开发测试环境由于是通过IP直连，需要跳过ssl验证
        disableSslVerification();
        // 将字符串转换为字节数组
//        byte[] stringBytes = requestJson.toString().getBytes(StandardCharsets.UTF_8);

        // 将字节数组转换为InputStream
//        InputStream inputStream = new ByteArrayInputStream(stringBytes);
        HttpEntity<String> entity = new HttpEntity<>(requestJson, headers);
        JSONObject resultJSON = restTemplate.execute(url, HttpMethod.POST, new RequestCallback() {
            @Override
            public void doWithRequest(ClientHttpRequest request) throws IOException {
                // 可以在这里设置请求头或请求体
                request.getHeaders().addAll(entity.getHeaders());
                OutputStream os = request.getBody();
                if (entity.getBody() != null) {
                    os.write(entity.getBody().getBytes());
                }
            }
        }, new ResponseExtractor<JSONObject>() {
            @Override
            public JSONObject extractData(ClientHttpResponse response) throws IOException {
                if (response.getStatusCode() != HttpStatus.OK) {
                    throw new YnceErrorException(YnceError.YNCE_000000);
                }
                StringBuilder result = new StringBuilder();
                InputStream inputStream = response.getBody();
                if (inputStream == null) {
                    throw new YnceErrorException(YnceError.YNCE_100002);
                }
                BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                }
                verifySign(result.toString());
                JSONObject jsonObject = JSONObject.parseObject(result.toString(), JSONObject.class);
                if (jsonObject.get("code").equals("00000")) {
                    return jsonObject.getJSONObject("response");
                } else {
                    if (jsonObject.get("msg") == null) {
                        throw new RuntimeException("发送请求异常");
                    }
                    throw new RuntimeException(jsonObject.get("msg").toString());
                }
            }
        });
        return resultJSON;
    }

    /**
     * 验证响应报文签名
     * 取出sign后，去掉sign，保持原来的key的顺序进行进行签名
     */
    private void verifySign(String responseBody){
        int index = responseBody.lastIndexOf("sign");
        String sign = responseBody.substring(index + 7, responseBody.length() - 2 );
        String source = responseBody.substring(0, index - 2) + "}";
        boolean pass = CryptoUtils.verifySign(SIGN_ALG, source, sign, publicKey, "UTF-8");
        if( !pass ){
            throw new RuntimeException("验签不通过");
        }
    }

    /**
     * 添加路径请求参数
     *
     * @param url          请求路径
     * @param urlParamsMap 请求路径参数集合(此参数)
     * @return 请求路径
     * @description
     * @author huabiao
     * @create 2023/5/30  17:18
     */
    private static String jointUrlParams(String url, Map<String, Object> urlParamsMap) {
        String requestUrl = url;
        if (BooleanUtils.isFalse(urlParamsMap.isEmpty())) {
            // 若RUL参数不为空则处理
            String urlParams = setUrlParams(urlParamsMap);
            if (url.contains("=")) {
                requestUrl += ("&" + urlParams);
            } else {
                requestUrl += ("?" + urlParams);
            }
        }
        return requestUrl;
    }

    /**
     * 设置URL参数
     *
     * @param params 请求参数
     * @return URL参数
     * @author huabiao
     * @create 2023/5/30  17:07
     */
    private static String setUrlParams(Map<String, Object> params) {
        Iterator<String> paramsIterator = params.keySet().iterator();
        StringBuilder paramsStringBuilder = new StringBuilder();
        while (paramsIterator.hasNext()) {
            String key = paramsIterator.next();
            if (params.get(key) == null || "".equals(params.get(key).toString())) {
                continue;
            }
            paramsStringBuilder.append("&").append(key).append("=").append(params.get(key));
        }
        // 去掉第一个&并返回
        return paramsStringBuilder.substring(1);
    }

    /**
     * 参数对象-格式化
     *
     * @param paramObject 参数对象
     * @return 对象
     * @description
     * @author huabiao
     * @create 2023/5/30  17:19
     */
    private static Object setParam(Object paramObject) {
        if (paramObject instanceof String) {
            return paramObject;
        }
        String requestJson = JSON.toJSONString(paramObject);
        if (paramObject == null || paramObject == "") {
            return JSON.toJSONString(new JSONObject());
        }

        // 如果是application/x-www-form-urlencoded请求方式就格式化数据
        if (MediaType.APPLICATION_FORM_URLENCODED.equals(headers.getContentType())) {
            return paramObject;
        }

        if (MediaType.TEXT_PLAIN.equals(headers.getContentType())) {
            return paramObject;
        }
        return requestJson;
    }
}
