package com.liquidnet.service.platform.utils;

import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.UserPathDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;

/**
 * <p>
 * 顺丰
 * </p>
 *
 * @author jiangxiulong
 * @since 2021-06-24 8:00 下午
 */
@Component
@Slf4j
public class ShunfengSignUtils {
    /**
     * appId
     */
    @Value("${liquidnet.shunfeng.appid}")
    private String APP_ID;
    /**
     * sk
     */
    @Value("${liquidnet.shunfeng.sk}")
    private String SK;
    /**
     * url
     */
    @Value("${liquidnet.shunfeng.url}")
    private String URL;
    /**
     * 签名有效期（可根据实际业务设定）单位：毫秒
     */
    private final static Long CHECK_TIME = 600000L;

    /**
     * 生成签名并请求
     * @param hbody 请求body
     * @return
     */
    public String generateSignatureAndRequest(HashMap<String, Object> hbody, String url) {
        long currentTimeMillis = System.currentTimeMillis(); // 时间戳
        String timestamp = currentTimeMillis + "";
        hbody.put("companyId", APP_ID);
        String body = JsonUtils.toJson(hbody);
        // 生成签名
        String sign = genSign(timestamp,body);

        CloseableHttpClient client = HttpClients.createDefault();
        // 请求下单地址
        HttpPost httpPost = new HttpPost(URL + url);
        // sendAppId（sendAppId需赋值appId）
        httpPost.addHeader("sendAppId", APP_ID);
        // 时间戳需和获取验签时一致！！！
        httpPost.addHeader("timestamp", timestamp);
        // 签名
        httpPost.addHeader("sign", sign);
        httpPost.addHeader("Content-Type", "application/json;charset=utf-8");
        httpPost.addHeader("Accept", "application/json");
        // 请求body体需和获取验签时一致且编码UTF8！！！
        httpPost.setEntity(new StringEntity(body, "utf-8"));
        CloseableHttpResponse response = null;
        log.info(UserPathDto.setData("header", "", httpPost.getAllHeaders()));
        log.info(UserPathDto.setData("body", "", body));

        try {
            response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                System.out.println("发送请求成功");
                HttpEntity entity = response.getEntity();
                // 发送响应且编码UTF8！！！
                return EntityUtils.toString(entity, "utf-8");
            }
        } catch (Exception e) {
            System.out.println("发送请求失败");
            e.printStackTrace();
        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 生成签名
     * @param timestamp 时间戳
     * @param body 请求body
     * @return
     */
    private String genSign(String timestamp, String body) {
        if (StringUtils.isEmpty(body)) {
            body = "";
        }

        StringBuffer sb = new StringBuffer();
        sb.append(body);
        sb.append("&sk=").append(SK);
        sb.append("&timestamp=").append(timestamp);

        byte[] bytes = DigestUtils.sha512(sb.toString());
        return Base64.encodeBase64URLSafeString(bytes);
    }



    /**
     * 接收请求且验签(可在控制层调用此方法)
     * @param params 接收请求参数
     * @param request 接收请求
     * @return
     */
    public boolean receiveRequestAndCheckSign(String params, HttpServletRequest request) {
        // 请求方APPID
        String sendAppId = request.getHeader("sendAppId");
        // 请求方时间戳
        String timestamp = request.getHeader("timestamp");
        // 请求方签名
        String sign = request.getHeader("sign");
        if (StringUtils.isBlank(sendAppId)) {
            System.out.println("参数sendAppId不能为空");
            return false;
        }
        if (StringUtils.isBlank(timestamp)) {
            System.out.println("参数timestamp不能为空");
            return false;
        }
        if (StringUtils.isBlank(sign)) {
            System.out.println("参数sign不能为空");
            return false;
        }
        // 校验签名是否过期
        long requestTime = Long.parseLong(timestamp);
        long now = System.currentTimeMillis();
        if (Math.abs(now - requestTime) > CHECK_TIME) {
            System.out.println("签名过期!");
            return false;
        }
        // 请求方参数+请求方时间戳+SK 生成签名
        String thisSign = genSign(timestamp, params);
        // 获取的签名和请求方签名比较是否一致
        if (!thisSign.equals(sign)) {
            System.out.println("签名错误");
            return false;
        }
        return true;
    }
}
