package com.cm.common.plugin.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cm.common.config.properties.OauthClientProperties;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * @ClassName: RestTemplateUtils
 * @Description: rest请求
 * @Author: WangGeng
 * @Date: 2019/4/22 4:43 PM
 * @Version: 1.0
 **/
@Component
public class RestTemplateUtil {

    private static Logger LOG = LoggerFactory.getLogger(RestTemplateUtil.class);
    @Autowired
    @Qualifier("oauth2ClientContext")
    private OAuth2ClientContext oAuth2ClientContext;
    @Autowired
    private OauthClientProperties oauthClientProperties;

    /**
     * 执行GET请求
     *
     * @param url
     * @param params
     * @return
     */
    public String doGetForm(String url, Map<String, Object> params) {
        refreshToken();
        String accessToken = getAccessToken();
        if (StringUtils.isBlank(accessToken)) {
            return null;
        }
        params.put("access_token", accessToken);
        RestTemplate restTemplate = getRestTemplate();
        try {
            LOG.debug("Rest Get Form:\nurl: {},\nparams: {}", url, params);
            return getResponse(restTemplate.getForEntity(String.format("%s?%s", url, queryParams(params)), String.class, params));
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 执行GET请求
     *
     * @param url
     * @param params
     * @return
     */
    public String doGetFormForApp(String token, String url, Map<String, Object> params) {
        RestTemplate restTemplate = getRestTemplate();
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        httpHeaders.add("token", token);
        HttpEntity<String> httpEntity = new HttpEntity<>(null, httpHeaders);
        try {
            LOG.debug("Rest get form for app:\ntoken: {},\nurl: {},\nparams: {}", token, url, params);
            return getResponse(restTemplate.exchange(String.format("%s?%s", url, queryParams(params)), HttpMethod.GET, httpEntity, String.class));
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 正常GET的form表单
     *
     * @param url
     * @param params
     * @return
     */
    public String doGetFormNormal(String url, Map<String, Object> params) {
        RestTemplate restTemplate = getRestTemplate();
        try {
            LOG.debug("Rest get form normal:\nurl: {},\nparams: {}", url, params);
            return getResponse(restTemplate.getForEntity(String.format("%s?%s", url, queryParams(params)), String.class, params));
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * post提交 form 数据
     *
     * @param url
     * @param params
     * @return
     */
    public String doPostForm(String url, Map<String, Object> params) {
        refreshToken();
        String accessToken = getAccessToken();
        if (StringUtils.isBlank(accessToken)) {
            return null;
        }

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String, Object> queryParams = new LinkedMultiValueMap<>();
        queryParams.add("access_token", accessToken);
        return doPost(url, params, httpHeaders, queryParams);
    }

    /**
     * app发送post表单请求
     *
     * @param token
     * @param url
     * @param params
     * @return
     */
    public String doPostFormForApp(String token, String url, Map<String, Object> params) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        httpHeaders.add("token", token);

        MultiValueMap<String, Object> queryParams = new LinkedMultiValueMap<>();
        return doPost(url, params, httpHeaders, queryParams);
    }

    /**
     * 正常POST的form表单
     *
     * @param url
     * @param params
     * @return
     */
    public String doPostFormNormal(String url, Map<String, Object> params) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String, Object> queryParams = new LinkedMultiValueMap<>();
        return doPost(url, params, httpHeaders, queryParams);
    }

    /**
     * 发送post请求
     *
     * @param url
     * @param params
     * @param httpHeaders
     * @param queryParams
     * @return
     */
    private String doPost(String url, Map<String, Object> params, HttpHeaders httpHeaders, MultiValueMap<String, Object> queryParams) {
        for (Map.Entry<String, Object> kv : params.entrySet()) {
            queryParams.add(kv.getKey(), kv.getValue());
        }
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(queryParams, httpHeaders);
        RestTemplate restTemplate = getRestTemplate();
        try {
            LOG.debug("Rest post:\nurl: {},\nhttpHeaders: {},\nqueryParams: {}", url, params, httpHeaders, queryParams);
            return getResponse(restTemplate.postForEntity(url, httpEntity, String.class));
        } catch (HttpClientErrorException e) {
            if (e.getRawStatusCode() == HttpStatus.BAD_REQUEST.value()) {
                return e.getResponseBodyAsString();
            }
            LOG.error(e.getMessage(), e);
            return null;
        }
    }

    public String doPostJsonForApp(String token, String url, Map<String, Object> params) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
        httpHeaders.add("token", token);
        HttpEntity<String> httpEntity = new HttpEntity<>(JSONObject.toJSONString(params), httpHeaders);
        RestTemplate restTemplate = getRestTemplate();
        try {
            LOG.debug("Rest post for app:\ntoken: {},\nurl: {},\nparams: {}", token, url, params);
            return getResponse(restTemplate.postForEntity(url, httpEntity, String.class));
        } catch (HttpClientErrorException e) {
            if (e.getRawStatusCode() == HttpStatus.BAD_REQUEST.value()) {
                return e.getResponseBodyAsString();
            }
            LOG.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求参数
     *
     * @param queryParams
     * @return
     */
    private String queryParams(Map<String, Object> queryParams) {
        if (queryParams == null) {
            return "";
        }
        StringBuilder urlParams = new StringBuilder();
        for (Map.Entry<String, Object> kv : queryParams.entrySet()) {
            if (urlParams.length() > 0) {
                urlParams.append("&");
            }
            urlParams.append(kv.getKey()).append("=").append(kv.getValue());
        }
        return urlParams.toString();
    }

    /**
     * @param responseEntity
     * @return
     */
    private String getResponse(ResponseEntity<String> responseEntity) {
        LOG.debug(">>>> 请求结果状态: {}, ", responseEntity.getStatusCodeValue());
        String response = responseEntity.getBody();
        if (HttpStatus.OK.value() == responseEntity.getStatusCodeValue()) {
            LOG.debug(response);
            if (response == null) {
                return new JSONObject().toJSONString();
            }
            return response;
        } else if (HttpStatus.UNAUTHORIZED.value() == responseEntity.getStatusCodeValue()) {
            return null;
        }
        return "";
    }

    /**
     * 获取restTemplate
     *
     * @return
     */
    private RestTemplate getRestTemplate() {
        SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
        simpleClientHttpRequestFactory.setConnectTimeout(20 * 1000);
        simpleClientHttpRequestFactory.setReadTimeout(60 * 1000);
        return new RestTemplate(simpleClientHttpRequestFactory);
    }

    /**
     * 刷新token
     *
     * @return
     */
    private void refreshToken() {
        if (oAuth2ClientContext.getAccessToken().getExpiresIn() < 1800) {
            LOG.debug("accessToken时间小于1800s，刷新token");
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            MultiValueMap<String, Object> queryParams = new LinkedMultiValueMap<>();
            queryParams.add("grant_type", "refresh_token");
            queryParams.add("refresh_token", oAuth2ClientContext.getAccessToken().getRefreshToken().getValue());
            queryParams.add("client_id", oauthClientProperties.getClientId());
            queryParams.add("client_secret", oauthClientProperties.getClientSecret());
            HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(queryParams, httpHeaders);
            RestTemplate restTemplate = getRestTemplate();
            try {
                String result = getResponse(restTemplate.postForEntity(oauthClientProperties.getAccessTokenUri(), httpEntity, String.class));
                if (!StringUtils.isBlank(result)) {
                    Map<String, String> tokenMap = JSON.parseObject(result, Map.class);
                    oAuth2ClientContext.setAccessToken(DefaultOAuth2AccessToken.valueOf(tokenMap));
                }
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 获取accessToken
     *
     * @return
     */
    private String getAccessToken() {
        return oAuth2ClientContext.getAccessToken().getValue();
    }

}
