package com.cpop.core.utils;

import com.alibaba.fastjson2.JSONObject;
import com.cpop.core.base.entity.CpopSignBase;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author DB
 * @version 1.0.0
 * @since 2024-02-28 14:50
 */
@Component
public class CpopSignatureUtils {

    @Autowired
    private RsaUtils rsaUtils;

    private static final Map<String, String[]> APP_IDS = new HashMap<String, String[]>() {{
        //数币
        put("1688842965582499840", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmsFHkB4iIdVSgaz8u8QG66wiZupgSbu2T/ml/kdPm2vemsKgvEqUqp1gR6ulfHcPF8otjVbjiE8q8oR70XfxFIREbomTUmpsOzurLFrAmVhyvu6/tY23/txjQoeeH/tlCy7Lq/TL1AqPKyBcGzsQ4yInpIgRWpXz7fmJCTRw07tyE+4lpXBqiaLdWrkkGG00LnHQAOfcUoXf0TdxFPSfRHiBikfbkmgeVoU66RGlUEXU2esTY2nYGvFn+FqWsNkGEnn2YxIqgbQQ1zNX33+FWBlba1WdQtc8mTJAleaPGXmFnQiEMb55b7xVPjyyCWt6aRwl97KQgtCmfsoPZUWwQQIDAQAB"});
        //系统
        put("100", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvDdtx3eLzoUbm0qr8xv4XXew0raUsv98eOmdxS4jDgFkajzK3H02fnWg99y2CRcZNnEFA6MlE/0RrAuWnuIehazQBR5dpnzoOht4WweRO0DEciRTdQ5Uf5T4YOlwmNKhE2S9jsmBP8X5Gi2r65G4miBG8r4AJJ9Pxtq8fjZUkCpKrk3y167mSunDUtZZOAimQ7W235Oh7fIqOSNQN+KxvhFSkiSqFIaXjDY50eONdSBaPYV1NsbW5A6VHrsvcG/2uzcEAfINFoRsmF9SxsckvnVsVfKgN+ONvnQdFmAJaiwtXJ9eJ4TfMt+HPTZk8pMfAUEj8vfz/98g39kKY42b2QIDAQAB"});
    }};

    /**
     * 发送签名http请求
     * @author DB
     * @since 2024/2/28
     * @param url 路径
     * @param data 数据
     * @param appid appid
     * @return Response
     */
    public JSONObject sendSignaturePost(String url, Object data, String appid) throws IOException, IllegalAccessException {
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        MediaType mediaType = MediaType.Companion.parse("application/json;charset=utf-8");
        RequestBody body = RequestBody.Companion.create(JSONObject.toJSONString(data), mediaType);
        String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String signType = "RSA";
        CpopSignBase cpopSignBase = new CpopSignBase();
        cpopSignBase.setSignType(signType);
        cpopSignBase.setDateTime(now);
        cpopSignBase.setAppId(appid);
        cpopSignBase.setSignature(md5(data, appid));
        Request request = new Request
                .Builder()
                .url(url)
                .post(body)
                .addHeader("Content-Type", "application/json")
                .addHeader("appId", appid)
                .addHeader("signature", signature(cpopSignBase,APP_IDS.get(appid)[0]))
                .addHeader("dateTime", now)
                .addHeader("signType", signType)
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
            return JSONObject.parseObject(response.body().string());
        } finally {
            assert response != null;
            response.close();
        }
    }

    private String md5(Object object, String appId) throws IllegalAccessException {
        //验签拼接字段
        List<String> signString = new ArrayList<String>();
        //获取父类（公共类必传属性）
        Field[] fatherFields = object.getClass().getSuperclass().getDeclaredFields();
        for (Field field : fatherFields) {
            field.setAccessible(true);
            signString.add(field.getName() + "=" + field.get(object));
        }
        //可能为空参
        Field[] fields = object.getClass().getDeclaredFields();
        if (fields.length > 0) {
            for (Field field : fields) {
                field.setAccessible(true);
                if (null == field.get(object)) {
                    signString.add(field.getName() + "=");
                } else {
                    signString.add(field.getName() + "=" + field.get(object));
                }
            }
        }
        //按照字母排序
        String sign = signString.stream().sorted().collect(Collectors.joining("&")) + appId;
        return DigestUtils.md5DigestAsHex(sign.getBytes());
    }

    /**
     * 签名
     *
     * @param data 数据
     * @return String
     * @author DB
     * @since 2024/2/28
     */
    private String signature(CpopSignBase data, String publicKey) {
        return rsaUtils.encrypt(JSONObject.toJSONString(data), stringToPublicKey(publicKey));
    }

    private PublicKey stringToPublicKey(String publicKey) {
        byte[] decode = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decode);
        //返回转换指定算法的KeyFactory对象
        KeyFactory keyFactory = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            //根据PKCS8编码密钥规范产生私钥对象
            return keyFactory.generatePublic(x509EncodedKeySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }
}
