package com.qmth.jkserver.util;

import com.qmth.jkserver.constant.SystemConstant;
import com.qmth.jkserver.core.exception.JkServerException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
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.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @Description: http util
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/12/11
 */
public class HttpUtil {
    private final static Logger log = LoggerFactory.getLogger(HttpUtil.class);

    /**
     * post 请求
     *
     * @param url
     * @param params
     * @param secret
     * @param timestamp
     * @return
     */
    public static String post(String url, Map<String, Object> params, String secret, Long timestamp) throws IOException {
        // 构建post请求
        HttpPost post = new HttpPost(url);
        post.setHeader(SystemConstant.HEADER_AUTHORIZATION, secret);
        post.setHeader(SystemConstant.HEADER_TIME, String.valueOf(timestamp));
        post.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=" + SystemConstant.CHARSET_NAME);
        // 构建请求参数
        List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
        if (!CollectionUtils.isEmpty(params)) {
            for (String key : params.keySet()) {
                pairs.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
            }
        }
        HttpEntity entity = null;
        try {
            entity = new UrlEncodedFormEntity(pairs, SystemConstant.CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
        post.setEntity(entity);
        // 执行请求，获取响应
        return getRespString(post);
    }

    /**
     * get 请求
     *
     * @param url
     * @param params
     * @param secret
     * @param timestamp
     * @return
     */
    public static String get(String url, Map<String, Object> params, String secret, Long timestamp) throws IOException {
        // 构建请求参数
        List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
        if (!CollectionUtils.isEmpty(params)) {
            for (String key : params.keySet()) {
                pairs.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
            }
        }
        String str = EntityUtils.toString(new UrlEncodedFormEntity(pairs, Consts.UTF_8));//转换为键值对
        HttpGet get = new HttpGet(url + "?" + str);
        if (Objects.nonNull(secret)) {
            get.setHeader(SystemConstant.HEADER_AUTHORIZATION, secret);
        }
        if (Objects.nonNull(timestamp)) {
            get.setHeader(SystemConstant.HEADER_TIME, String.valueOf(timestamp));
        }
        // 执行请求，获取响应
        return getRespString(get);
    }

    /**
     * 获取响应信息
     *
     * @param request
     * @return
     */
    public static String getRespString(HttpUriRequest request) throws IOException {
        // 获取响应流
        InputStream in = null;
        ByteArrayOutputStream ou = null;
        try {
            in = getRespInputStream(request);
            ou = new ByteArrayOutputStream();
            IOUtils.copy(in, ou);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        } finally {
            if (Objects.nonNull(in)) {
                in.close();
            }
            if (Objects.nonNull(ou)) {
                ou.close();
            }
        }
        return Objects.nonNull(ou) ? new String(ou.toByteArray(), StandardCharsets.UTF_8) : null;
    }

    /**
     * 获取输入流
     *
     * @param request
     * @return
     */
    public static InputStream getRespInputStream(HttpUriRequest request) {
        // 获取响应对象
        HttpResponse response = null;
        try {
            response = HttpClients.createDefault().execute(request);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
        if (response == null) {
            return null;
        }
        // 获取Entity对象
        HttpEntity entity = response.getEntity();
        // 获取响应信息流
        InputStream in = null;
        if (entity != null) {
            try {
                in = entity.getContent();
            } catch (Exception e) {
                log.error(SystemConstant.LOG_ERROR, e);
            }
        }
        return in;
    }

    /**
     * 根据url下载文件，保存到filePath中
     *
     * @param url
     * @param filePath
     * @return
     */
    public static File httpDownload(String url, String filePath) throws IOException {
        InputStream is = null;
        File file = null;
        try {
            HttpClient client = HttpClients.createDefault();
            HttpGet httpget = new HttpGet(url);
            HttpResponse response = client.execute(httpget);

            HttpEntity entity = response.getEntity();
            is = entity.getContent();

            Optional.ofNullable(is).orElseThrow(() -> new JkServerException("所在路径不存在"));
            file = new File(filePath);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            FileUtils.copyInputStreamToFile(is, file);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        } finally {
            if (Objects.nonNull(is)) {
                is.close();
            }
        }
        return file;
    }

    /**
     * post file
     *
     * @param url
     * @param params
     * @param secret
     * @param timestamp
     * @return
     * @throws IOException
     */
    public static String postFile(String url, Map<String, Object> params, String secret, Long timestamp) throws IOException {
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(SystemConstant.CONNECT_TIME_OUT)// 连接主机服务超时时间
                .setConnectionRequestTimeout(SystemConstant.CONNECT_TIME_OUT)// 请求超时时间
                .setSocketTimeout(SystemConstant.SOCKET_CONNECT_TIME_OUT)// 数据读取超时时间
                .build();
        HttpPost post = new HttpPost(url);
        post.setHeader(SystemConstant.HEADER_AUTHORIZATION, secret);
        post.setHeader(SystemConstant.HEADER_TIME, String.valueOf(timestamp));

        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
        // 解决中文文件名乱码问题
        entityBuilder.setMode(HttpMultipartMode.RFC6532);
        entityBuilder.setCharset(Consts.UTF_8);
        ContentType contentType = ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), Consts.UTF_8);

        // 构建请求参数
        if (!CollectionUtils.isEmpty(params)) {
            for (String key : params.keySet()) {
                if (key.contains("file")) {
                    File file = new File((String) params.get(key));
                    entityBuilder.addBinaryBody(key, file, ContentType.DEFAULT_BINARY, file.getName());
                } else {
//                    entityBuilder.addTextBody(key, String.valueOf(params.get(key)), contentType);
                    StringBody stringBody = new StringBody(String.valueOf(params.get(key)), contentType);
                    entityBuilder.addPart(key, stringBody);
                }
            }
        }
        post.setEntity(entityBuilder.build());
        post.setConfig(requestConfig);
        return getRespString(post);
    }

    /**
     * post json
     *
     * @param url
     * @param json
     * @param secret
     * @param timestamp
     * @return
     * @throws IOException
     */
    public static String postJson(String url, String json, String secret, Long timestamp) throws IOException {
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(SystemConstant.CONNECT_TIME_OUT)// 连接主机服务超时时间
                .setConnectionRequestTimeout(SystemConstant.CONNECT_TIME_OUT)// 请求超时时间
                .setSocketTimeout(SystemConstant.SOCKET_CONNECT_TIME_OUT)// 数据读取超时时间
                .build();
        // 构建post请求
        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);
        post.setHeader(SystemConstant.HEADER_AUTHORIZATION, secret);
        post.setHeader(SystemConstant.HEADER_TIME, String.valueOf(timestamp));
        post.setHeader(HTTP.CONTENT_TYPE, SystemConstant.CONTENT_TYPE_JSON + "; charset=" + SystemConstant.CHARSET_NAME);
        post.setHeader("Accept", SystemConstant.CONTENT_TYPE_JSON);

        String encoderJson = URLEncoder.encode(json, SystemConstant.CHARSET_NAME);
        StringEntity se = new StringEntity(encoderJson);
        se.setContentType("text/json");
        se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, SystemConstant.CONTENT_TYPE_JSON));
        post.setEntity(se);
        // 执行请求，获取响应
        return getRespString(post);
    }

    /**
     * post json
     *
     * @param url
     * @param json
     * @param headers
     * @return
     * @throws IOException
     */
    public static String postJson(String url, String json, Map<String, String> headers) throws IOException {
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(SystemConstant.CONNECT_TIME_OUT)// 连接主机服务超时时间
                .setConnectionRequestTimeout(SystemConstant.CONNECT_TIME_OUT)// 请求超时时间
                .setSocketTimeout(SystemConstant.SOCKET_CONNECT_TIME_OUT)// 数据读取超时时间
                .build();
        // 构建post请求
        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            post.setHeader(entry.getKey(), entry.getValue());
        }

//        String encoderJson = URLEncoder.encode(json, SystemConstant.CHARSET_NAME);
//        StringEntity se = new StringEntity(encoderJson);
        StringEntity se = new StringEntity(json);
        se.setContentType("text/json");
        se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, SystemConstant.CONTENT_TYPE_JSON));
        post.setEntity(se);
        // 执行请求，获取响应
        return getRespString(post);
    }

    /**
     * post file
     *
     * @param url
     * @param params
     * @param headers
     * @return
     * @throws IOException
     */
    public static String postFile(String url, Map<String, Object> params, Map<String, String> headers) throws IOException {
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(SystemConstant.CONNECT_TIME_OUT)// 连接主机服务超时时间
                .setConnectionRequestTimeout(SystemConstant.CONNECT_TIME_OUT)// 请求超时时间
                .setSocketTimeout(SystemConstant.SOCKET_CONNECT_TIME_OUT)// 数据读取超时时间
                .build();
        HttpPost post = new HttpPost(url);
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            post.setHeader(entry.getKey(), entry.getValue());
        }

        File file = null;
        try {
            MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
            // 解决中文文件名乱码问题
            entityBuilder.setMode(HttpMultipartMode.RFC6532);
            entityBuilder.setCharset(Consts.UTF_8);
            ContentType contentType = ContentType.create(ContentType.MULTIPART_FORM_DATA.getMimeType(), Consts.UTF_8);
            if (!CollectionUtils.isEmpty(params)) {
                for (String key : params.keySet()) {
                    if (key.contains("files")) {
                        MultipartFile multipartFile = (MultipartFile) params.get(key);
                        String[] strs = StringUtils.split(multipartFile.getOriginalFilename(), ".");
                        file = SystemConstant.getFileTempVar("." + strs[1]);
                        FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
                        entityBuilder.addBinaryBody(key, file, ContentType.DEFAULT_BINARY, file.getName());
                    } else {
                        entityBuilder.addPart(key, new StringBody(String.valueOf(params.get(key)), contentType));
                    }
                }
            }
            entityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA);
            post.setEntity(entityBuilder.build());
            post.setConfig(requestConfig);
            return getRespString(post);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(file)) {
                file.delete();
            }
        }
        return null;
    }
}
