package com.zzwtec.third.config.restful;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.zzwtec.third.common.WebPrefixAndConstant;
import com.zzwtec.third.utils.BizException;
import com.zzwtec.third.utils.RequestObject;
import com.zzwtec.third.utils.ResultObject;
import com.zzwtec.third.utils.encryption.EncoderHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * create by Jomchen on 2018/11/30
 */
@Service
public class RestfulService {

    private Logger logger = LoggerFactory.getLogger(RestfulService.class);

    @Value("${weChat.app-id}")
    private String appid;
    @Value("${weChat.app-secret}")
    private String secretKey;
    @Autowired
    private RestTemplate restTemplate;


    /**
     * 远程请求
     * @param httpHeaders   自定义请求头
     * @param url   请求地址
     * @param t  请求实体
     * @param typeReference 预计反序列化的类型的泛型对象
     */
    public <T, R> R postExecute(
            HttpHeaders httpHeaders,
            String url,
            T t,
            TypeReference<R> typeReference) {

        HttpHeaders usedHttpHeaders = (null == httpHeaders) ?
                RestfulConfig.getHttpHeaders() : httpHeaders;
        HttpEntity<T> httpEntity = new HttpEntity<>(t, usedHttpHeaders);
        ResponseEntity<String> responseEntity;
        try {
            responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
        } catch (Exception e) {
            logger.error("远程请求失败：" + e.getMessage());
            throw e;
        }

        String resultStr = responseEntity.getBody();
        try {
            return JSONObject.parseObject(resultStr, typeReference);
        } catch (Exception e) {
            logger.error("反序列化失败：" + e.getMessage());
            throw e;
        }
    }

    /**
     * 调用 openapi 的方法
     * @param url 请求地址
     * @param p 请求对象
     * @param typeReference 反序列化的包装
     * @param <P> 请求的泛型
     * @param <R> 想获取的数据的对象
     */
    @SuppressWarnings("unchecked")
    public <P, R> R postOpenApi(
            String url,
            P p,
            TypeReference<ResultObject<R>> typeReference) throws BizException {

        RequestObject<P> requestObject = RequestObject.build(p);
        /* --------------------------
            严重注意！！
            这里的序列化参数的控件 和 Restful(远程请求组件)的序列化控件
                                                 和 远程方的序列化控件和序列化特征 一定要相同
            因为这里参数序列化后为 A
            Restful序列化数据为 B
            远程方的接收参数序列化为 C
            如果三者不能保证统一，则在传输过程中会因为输出结果不一致而签名失败
         -----------------------------*/
        String bodyJson = JSONObject.toJSONString(requestObject);
        String bodySign = bodyJson + secretKey;
        String encryption = EncoderHandler.MD5(bodySign);
        String headerValue = String.format(
                WebPrefixAndConstant.OPENAPI_HEADER_DEMO,
                appid,
                encryption
        );
        HttpHeaders httpHeaders = RestfulConfig.getHttpHeaders(
                WebPrefixAndConstant.OPENAPI_HEADER,
                headerValue
        );

        ResultObject<R> resultObject = postExecute(
                httpHeaders,
                url,
                requestObject,
                typeReference
        );
        ResultObject.isOk(resultObject);
        return resultObject.getData();
    }


}
