package com.liquidnet.service.platform.utils;

import com.liquidnet.commons.lang.constant.LnsEnum;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
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.entity.StringEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

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

    @Autowired
    Environment environment;

    /**
     * 生成签名并请求
     * @param hbody 请求body
     * @return
     */
    public String generateSignatureAndRequestNew(Map<String, String> 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);

        Map<String, String> headers = new HashMap<>();
        headers.put("sendAppId", APP_ID);
        headers.put("timestamp", timestamp);
        headers.put("sign", sign);
        headers.put("Content-Type", "application/json;charset=utf-8");
        headers.put("Accept", "application/json");
        Map<String, String> querys = new HashMap<>();
        try {
            HttpEntity httpEntity = new StringEntity(body, "utf-8");
            log.info("generateSignatureAndRequestNew body:[{}], headers:[{}]", body, headers);
            String post = HttpsUtils.post(URL + url, headers, querys, httpEntity);
            return post;
        } catch (Exception e) {
            System.out.println("发送请求失败");
            e.printStackTrace();
            return e.getMessage();
        }
    }


    /**
     * 生成签名
     * @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) {
        if (Arrays.asList(LnsEnum.ENV.dev.name(), LnsEnum.ENV.test.name()).contains(environment.getProperty(CurrentUtil.CK_ENV_ACTIVE))) {
            return true;
        }
        log.debug("params {}", params);
        // 请求方APPID
        String sendAppId = request.getHeader("sendAppId");
        // 请求方时间戳
        String timestamp = request.getHeader("timestamp");
        // 请求方签名
        String sign = request.getHeader("sign");

        if (StringUtils.isBlank(sendAppId)) {
            log.error("参数sendAppId不能为空");
            return false;
        }
        if (StringUtils.isBlank(timestamp)) {
            log.error("参数timestamp不能为空");
            return false;
        }
        if (StringUtils.isBlank(sign)) {
            log.error("参数sign不能为空");
            return false;
        }
        // 校验签名是否过期
        long requestTime = Long.parseLong(timestamp);
        long now = System.currentTimeMillis();
        if (Math.abs(now - requestTime) > CHECK_TIME) {
            log.error("签名过期");
            return false;
        }
        // 请求方参数+请求方时间戳+SK 生成签名
        String thisSign = genSign(timestamp, params);
        // 获取的签名和请求方签名比较是否一致
        if (!thisSign.equals(sign)) {
            log.error("签名错误");
            return false;
        }
        return true;
    }
}
