package cn.hmsoft.hmplatform.helper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
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.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import com.google.gson.Gson;

import cn.hmsoft.helper.LocalDateHelper;
import cn.hmsoft.hmplatform.identity.baidu.OpenApiParamUtil;
import cn.hmsoft.log.LogHelper;

public class HttpClientHelper {
	
	private static final int TIMEOUT = 10 * 1000;
	private static CloseableHttpClient httpClient = null;
	private final static Object syncLock = new Object();
	public static CookieStore cookieStore = new BasicCookieStore();
	
	private HttpClientHelper() {
		
	}
	
	private static void config(HttpRequestBase base) {
		RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(TIMEOUT)
                .setConnectTimeout(TIMEOUT)
                .setSocketTimeout(TIMEOUT)
                .build();
		//base.setProtocolVersion(HttpVersion.HTTP_1_0);
		base.setConfig(requestConfig);
	}
	
	public static CloseableHttpClient getHttpClient(String url) {
        if (httpClient == null) {
            synchronized (syncLock) {
                if (httpClient == null) {
                    httpClient = createHttpClient(200, 40, 100, url);
                }
            }
        }
        return httpClient;
    }
	
	public static CloseableHttpClient createHttpClient(int maxTotal,
            int maxPerRoute, int maxRoute, String url) {
        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder
                .<ConnectionSocketFactory> create()
                .register("http", plainsf)
                .register("https", sslsf)
                .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
        // 将最大连接数增加
        cm.setMaxTotal(maxTotal);
        // 将每个路由基础的连接增加
        cm.setDefaultMaxPerRoute(maxPerRoute);
        HttpHost httpHost = new HttpHost(url);
        // 将目标主机的最大连接数增加
        cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);
 
        // 请求重试处理
        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
            public boolean retryRequest(IOException exception,
                    int executionCount, HttpContext context) {
                if (executionCount >= 5) {// 如果已经重试了5次，就放弃
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超时
                    return false;
                }
                if (exception instanceof UnknownHostException) {// 目标服务器不可达
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                    return false;
                }
                if (exception instanceof SSLException) {// SSL握手异常
                    return false;
                }
 
                HttpClientContext clientContext = HttpClientContext
                        .adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果请求是幂等的，就再次尝试
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };
 
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(cm)
                .setRetryHandler(httpRequestRetryHandler)
                .build();
 
        return httpClient;
    }
	
	private static void setPostParams(HttpPost httpost, Map<String, Object> params) {
        //List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        for (String key : keySet) {
        	Object param = params.get(key);
    		if (param.getClass().isArray()) {
				//字符串数组
    			Object[] arr = (Object[])param;
    			for (Object val : arr) {
    				builder.addPart(key, new StringBody(val.toString(), ContentType.TEXT_PLAIN));
    			}
    		} else {
    			//nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
    			builder.addPart(key, new StringBody(params.get(key).toString(), ContentType.TEXT_PLAIN));
    		}
        }
        httpost.setEntity(builder.build());//new UrlEncodedFormEntity(nvps, "UTF-8")
    }
	
	/**
	 * post请求.
	 * @param url
	 * @param params
	 * @param headers
	 * @return
	 * @throws IOException
	 */
	public static String post(String url, Map<String, Object> params) throws IOException {
        HttpPost httppost = new HttpPost(url);
        config(httppost);
        setPostParams(httppost, params);
        CloseableHttpResponse response = null;
        //httppost.setHeader("Content-type", "application/x-www-form-urlencoded");
        try {
            response = getHttpClient(url).execute(httppost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (response != null) {
                	response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
	/**
	 * post请求json.
	 * @param url
	 * @param requestBody
	 * @param headers
	 * @return
	 * @throws IOException
	 */
	public static String postJson(String url, String requestBody, Map<String, Object> headers) throws IOException {
        HttpPost httppost = new HttpPost(url);
        config(httppost);
        StringEntity requestEntity = new StringEntity(requestBody, "utf-8");
        requestEntity.setContentEncoding("UTF-8");
        httppost.setHeader("Content-type", "application/json");
        httppost.setEntity(requestEntity);
        
        for (String key : headers.keySet()) {
        	httppost.setHeader(key, headers.get(key).toString());
        }
        
        CloseableHttpResponse response = null;
        try {
            response = getHttpClient(url).execute(httppost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (response != null) {
                	response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
	/**
	 * get请求.
	 * @param url
	 * @return
	 * @throws IOException 
	 */
	public static String get(String url) throws IOException {
        HttpGet httpget = new HttpGet(url);
        config(httpget);
        CloseableHttpResponse response = null;
        try {
            response = getHttpClient(url).execute(httpget, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            EntityUtils.consume(entity);
            return result;
        } catch (IOException e) {
            throw e;
        } finally {
            try {
                if (response != null) {
                	response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
	/**
	 * get请求.
	 * @param url
	 * @param params
	 * @return
	 * @throws IOException 
	 * @throws URISyntaxException 
	 */
	public static String get(String url, Map<String, Object> params) throws IOException, URISyntaxException {
        CloseableHttpResponse response = null;
        try {
			final URIBuilder builder = new URIBuilder(url);
			for (String key : params.keySet()) {
				builder.setParameter(key, params.get(key).toString());
			}
            HttpGet httpget = new HttpGet(builder.build());
            config(httpget);
            response = getHttpClient(url).execute(httpget, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            EntityUtils.consume(entity);
            return result;
        } catch (IOException e) {
            throw e;
        } catch (URISyntaxException e) {
        	throw e;
		} finally {
            try {
                if (response != null) {
                	response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
	public static void download(String url, Map<String, Object> params, String storePath) {
		CloseableHttpResponse response = null;
		try {
			final URIBuilder builder = new URIBuilder(url);
			for (String key : params.keySet()) {
				builder.setParameter(key, params.get(key).toString());
			}
			final HttpGet httpGet = new HttpGet(builder.build());
			response = getHttpClient(url).execute(httpGet);
			HttpEntity httpEntity = response.getEntity();
			InputStream is = httpEntity.getContent();
			/*ByteArrayOutputStream output = new ByteArrayOutputStream();
			byte[] buffer = new byte[4096];
			int r = 0;
            while ((r = is.read(buffer)) > 0) {
                output.write(buffer, 0, r);
            }
            FileOutputStream fos = new FileOutputStream(filePath);
            output.writeTo(fos);
            output.flush();
            output.close();
            fos.close();*/
			FileOutputStream fos = new FileOutputStream(storePath);
            IOUtils.copy(is, fos);
            fos.flush();
            fos.close();
            EntityUtils.consume(httpEntity);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} finally {
            try {
				response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
        }
	}
	
	
	public static void main1(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, FileNotFoundException, IOException {
		String url = "https://aip.baidubce.com/rest/2.0/face/v3/match?access_token=24.220d96af439f0e4988592bd4c6ffa5be.2592000.1601110163.282335-17794270";
		//头部参数
		Map<String, Object> headerMap = new HashMap<String, Object>();
		//创建请求参数
		Set<Object> param = new HashSet<Object>();
		
		Map<String, Object> pic1Map = new HashMap<String, Object>();
		pic1Map.put("image", Base64.getEncoder().encodeToString(org.apache.commons.io.IOUtils.toByteArray(new FileInputStream(new File("C:\\Users\\Lenovo\\Desktop\\1.png")))));
		pic1Map.put("image_type", "BASE64");
		pic1Map.put("face_type", "LIVE");
		pic1Map.put("quality_control", "NONE");//质量要求要低
		pic1Map.put("liveness_control", "NONE");
		
		Map<String, Object> pic2Map = new HashMap<String, Object>();
		pic2Map.put("image", Base64.getEncoder().encodeToString(org.apache.commons.io.IOUtils.toByteArray(new FileInputStream(new File("C:\\Users\\Lenovo\\Desktop\\2.png")))));
		pic2Map.put("image_type", "BASE64");
		pic2Map.put("face_type", "LIVE");
		pic2Map.put("quality_control", "NONE");//质量要求要低
		pic2Map.put("liveness_control", "NONE");
		
		param.add(pic1Map);
		param.add(pic2Map);
		
		Gson gson = new Gson();
		String requestBody = gson.toJson(param);
		System.out.println(requestBody);
		//执行请求
		try {
			long startTime = System.currentTimeMillis();
			String json = HttpClientHelper.postJson(url, requestBody, headerMap);
			long endTime = System.currentTimeMillis();
			
			System.out.println("比对结果-----> " + json);
			System.out.println("执行时间: " + (endTime-startTime)/1000.0);
			
		} catch(Exception e) {
			LogHelper.error(e);
		}
	}
	
	public static void main2(String[] args) {
		String url = "https://tsn.baidu.com/text2audio";
		//创建请求参数
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("tex", "测试百度语音播放功能，注意音量和速度变化。");
		paramMap.put("tok", "24.43b4d25d924343bc66d12d578dd63668.2592000.1601800544.282335-22552887");
		paramMap.put("cuid", "195842001485244520");
		paramMap.put("ctp", "1");//web端固定为1
		paramMap.put("lan", "zh");
		paramMap.put("spd", "5");
		paramMap.put("pit", "5");
		paramMap.put("vol", "5");
		paramMap.put("per", "0");
		paramMap.put("aue", "3");//默认MP3
		//执行请求
		try {
			long startTime = System.currentTimeMillis();
			String json = HttpClientHelper.post(url, paramMap);
			long endTime = System.currentTimeMillis();
			
			System.out.println("比对结果-----> " + json);
			System.out.println("执行时间: " + (endTime-startTime)/1000.0);
			
		} catch(Exception e) {
			LogHelper.error(e);
		}
	}
	
	public static void main3(String[] args) {
		String url = "http://tsn.baidu.com/text2audio";
	    String params = "tex=" + OpenApiParamUtil.urlEncode(OpenApiParamUtil.urlEncode("测试百度语音播放功能，注意音量和速度变化。"));
        params += "&per=0";
        params += "&spd=5";
        params += "&pit=5";
        params += "&vol=5";
        params += "&cuid=195842001485244520";
        params += "&tok=" + "24.43b4d25d924343bc66d12d578dd63668.2592000.1601800544.282335-22552887";
        params += "&aue=3";//下载的文件格式, 3：mp3(default) 4： pcm-16k 5： pcm-8k 6. wav
        params += "&lan=zh&ctp=1";
        try {
	        //执行请求
	        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
	        conn.setDoInput(true);
	        conn.setDoOutput(true);
	        conn.setConnectTimeout(5000);
	        PrintWriter printWriter = new PrintWriter(conn.getOutputStream());
	        printWriter.write(params);
	        printWriter.close();
	        String contentType = conn.getContentType();
	        if (contentType.contains("audio/")) {
	            byte[] bytes = OpenApiParamUtil.getResponseBytes(conn);
	            String format = getFormat(3);
	            File file = new File("result." + format); // 打开mp3文件即可播放
	            // System.out.println( file.getAbsolutePath());
	            FileOutputStream os = new FileOutputStream(file);
	            os.write(bytes);
	            os.close();
	            System.out.println("audio file write to " + file.getAbsolutePath());
	        } else {
	            System.err.println("ERROR: content-type= " + contentType);
	            String res = OpenApiParamUtil.getResponseString(conn);
	            System.err.println(res);
	        }
        } catch(Exception e) {
        	e.printStackTrace();
        }
	}
	
    // 下载的文件格式, 3：mp3(default) 4： pcm-16k 5： pcm-8k 6. wav
    private static String getFormat(int aue) {
        String[] formats = {"mp3", "pcm", "pcm", "wav"};
        return formats[aue - 3];
    }
    
    public static void main(String[] args) {
//		String str = "{\"login\":true,\"success\":true,\"entity\":{\"access_token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJxbWhtIiwiY2VydF9pZCI6IjY1MjMwMjE5ODUxMDAxMTUzNCIsInN0ZF9pZCI6MSwiZXhwIjoxNjAyNzI2MDU3LCJpYXQiOjE2MDI3MjUzMzd9.se-kYC0T-Vgt85YhBGl8dvRuKDVBDDp_QNVbJVBjKjs\",\"std_id\":1,\"cert_id\":\"652302198510011534\",\"std_name\":\"陈永生\",\"expire_time\":\"2020-10-15 09:40:57\",\"mills\":720000,\"login_times\":0,\"oss_encrypt_json\":\"iiNvZ/z9doFzLiGjpGfPjgn5VPOcj01mJWUSrg69jHC8cv+Uor3CRmhc+3w2cFhHw73y3t+/Gvr4/0hk9SAWN8pNCuOiYEX/n8gahxwAtge876KnRxneWtpGGxQsqLvNKw9R/ZD7EMrpgaRBdKoOE4DN0hhbKXsXd/Tt/Kk6lLJG3QAVyjAgyFKHDH+vUjNzicCA+r5LiJVENbL8Ip+ujg==\"},\"errorCode\":0}";
//	
//		String date = LocalDateHelper.format(LocalDateTime.now());
//		System.out.println(date);
//		
//		long expireMills = System.currentTimeMillis() + 5000;
//		String date2 = LocalDateHelper.format(LocalDateTime.ofEpochSecond(expireMills/1000, 0, ZoneOffset.ofHours(8)));
//		System.out.println(date2);
    	String url = "https://qmhm.oss-cn-beijing.aliyuncs.com/mr2022/10048/12345678/6087/hJCikkdbcX.pdf";
    	Map<String, Object> params = new HashMap<>();
    	download(url, params, "D:/data/1.pdf");
		
    }
}