package com.yiqi.common.utils.wx;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.yiqi.common.exception.ServiceException;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author xiaohei
 * @date 2024/2/3
 */
public class AES_Dec {

    public static String getRealResp(WxAppApiAESSecretDTO ctx, int respTs,String respData) {
        System.out.println("respTs:" + respTs);
        System.out.println("respData:" + respData);
        byte[] decryptedBytes = null;
        // 开发者本地信息
        String local_appid = ctx.getAppId();
        String url_path = ctx.getUrlPath();
        String local_sym_sn = ctx.getSn();
        String local_sym_key = ctx.getKey();
        // API响应数据，解密只需要响应头时间戳与响应数据

        JsonParser parser = new JsonParser();
        JsonElement resp_data = parser.parse(respData);
        String iv = resp_data.getAsJsonObject().get("iv").getAsString();
        String data = resp_data.getAsJsonObject().get("data").getAsString();
        String authtag = resp_data.getAsJsonObject().get("authtag").getAsString();
        // 构建AAD
        String aad = url_path + "|" + local_appid + "|" + respTs + "|" + local_sym_sn;
        // 拼接cipher和authtag
        byte[] dataBytes = Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8));
        byte[] authtagBytes = Base64.getDecoder().decode(authtag.getBytes(StandardCharsets.UTF_8));
        byte[] new_dataBytes = new byte[dataBytes.length + authtagBytes.length];
        System.arraycopy(dataBytes, 0, new_dataBytes, 0, dataBytes.length);
        System.arraycopy(authtagBytes, 0, new_dataBytes, dataBytes.length, authtagBytes.length);
        byte[] aadBytes = aad.getBytes(StandardCharsets.UTF_8);
        byte[] ivBytes = Base64.getDecoder().decode(iv.getBytes(StandardCharsets.UTF_8));
        String decryptedData = null;
        try {
            byte[] keyBytes = Base64.getDecoder().decode(local_sym_key.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
            cipher.updateAAD(aadBytes);
            decryptedBytes = cipher.doFinal(new_dataBytes);

            // 解密结果
            decryptedData = new String(decryptedBytes, StandardCharsets.UTF_8);
            JsonElement element = parser.parse(decryptedData);
            Gson gson = new Gson();
//            realResp = gson.fromJson(element, Object.class);
            long localTs = System.currentTimeMillis() / 1000;
            // 安全检查，根据业务实际需求判断
            if (element.getAsJsonObject().get("_appid").getAsString() == local_appid // appid不匹配
                    || element.getAsJsonObject().get("_timestamp").getAsLong() != respTs // timestamp与Wechatmp-TimeStamp不匹配
                    || localTs - element.getAsJsonObject().get("_timestamp").getAsLong() > 300 // 响应数据的时候与当前时间超过5分钟
            ) {
                System.out.println("安全字段校验失败");
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
        return decryptedData;
    }

    public static Object getRealResp(JsonObject ctx,JsonObject resp){
        byte[] decryptedBytes = null;
        // 开发者本地信息
        String local_appid = ctx.get("local_appid").getAsString();
        String url_path = ctx.get("url_path").getAsString();
        String local_sym_sn = ctx.get("local_sym_sn").getAsString();
        String local_sym_key = ctx.get("local_sym_key").getAsString();
        // API响应数据，解密只需要响应头时间戳与响应数据
        long respTs = resp.get("resp_ts").getAsLong();
        String respData = resp.get("resp_data").getAsString();

        JsonParser parser = new JsonParser();
        JsonElement resp_data = parser.parse(respData);
        String iv = resp_data.getAsJsonObject().get("iv").getAsString();
        String data = resp_data.getAsJsonObject().get("data").getAsString();
        String authtag = resp_data.getAsJsonObject().get("authtag").getAsString();
        // 构建AAD
        String aad = url_path + "|" + local_appid + "|" + respTs + "|" + local_sym_sn;
        // 拼接cipher和authtag
        byte[] dataBytes = Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8));
        byte[] authtagBytes = Base64.getDecoder().decode(authtag.getBytes(StandardCharsets.UTF_8));
        byte[] new_dataBytes = new byte[dataBytes.length+authtagBytes.length];
        System.arraycopy(dataBytes,0,new_dataBytes,0,dataBytes.length);
        System.arraycopy(authtagBytes,0,new_dataBytes,dataBytes.length,authtagBytes.length);
        byte[] aadBytes = aad.getBytes(StandardCharsets.UTF_8);
        byte[] ivBytes = Base64.getDecoder().decode(iv.getBytes(StandardCharsets.UTF_8));
        Object realResp = null;
        try
        {
            byte[] keyBytes = Base64.getDecoder().decode(local_sym_key.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
            cipher.updateAAD(aadBytes);
            try{
                decryptedBytes = cipher.doFinal(new_dataBytes);
            }catch (Exception e){
                System.out.println("auth tag验证失败");
                e.printStackTrace();
                return null;
            }

            // 解密结果
            String decryptedData = new String(decryptedBytes, StandardCharsets.UTF_8);
            JsonElement element = parser.parse(decryptedData);
            Gson gson = new Gson();
            realResp = gson.fromJson(element,Object.class);
            long localTs = System.currentTimeMillis() / 1000;
            // 安全检查，根据业务实际需求判断
            if (element.getAsJsonObject().get("_appid").getAsString() == local_appid // appid不匹配
                    || element.getAsJsonObject().get("_timestamp").getAsLong() != respTs // timestamp与Wechatmp-TimeStamp不匹配
                    || localTs - element.getAsJsonObject().get("_timestamp").getAsLong() > 300 // 响应数据的时候与当前时间超过5分钟
            ) {
                System.out.println("安全字段校验失败");
                return null;
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return realResp;

    }

    private static JsonObject getCtx(){
        JsonObject ctx = new JsonObject();
        // 仅做演示，敏感信息请勿硬编码
        ctx.addProperty("local_sym_key","tKSMHIDoAVW+C1VKAetjI+c1rYhy+Y4LBpNcJz7QUIo=");
        ctx.addProperty("local_sym_sn","40483f81f24d63c61a0cc15af850cf5b");
        ctx.addProperty("local_appid","wx439b59310024fa6f");
        ctx.addProperty("url_path","https://api.weixin.qq.com/cgi-bin/express/intracity/querystore");

        return ctx;
    }
    private static JsonObject getResp(){
        JsonObject resp = new JsonObject();
        String respData = "{\"iv\":\"8t5JY41vTCYx96zF\",\"data\":\"HlPz81AtpAngiwstPcbtej42gELx0JYYk+7fgZCK\\/sTGRSgI21NMzaMfmra9V2Vx30uY6cdXB8sfH972g7\\/I9mke7qgFJTG+DWlCzPBlY\\/ruZrsnoiPx0EuBCk+rc\\/cLFbN4QJT5Q+i7JXPKnz7tBmEtPj4FGQOMRGx9WV43ZiTHH6KkG8eHfNefdiNoRd+RXSMSNYCM4HDiY4VJBMqfVbZ35r4F8WoykbD4WuRIzgI6sttMBWg7H\\/Wuhh69+wmRPQg3xZ26FsJ3PT1wlpvxgNH+HOSFDRgc4Joqadk9EcqE+imU8XJFOWnfeS0LdZ+IVFTUEU68XKwdi6RdER5aEBk2JtRXvzLzfNky3PZTmz37Psto0gJufk\\/1xH2+jcehfa53tE8uqfjaY3SUJHkiM1zc7f51rRWmZv2z36hjFKuDIsj\\/cwWdPNP83\\/ST48+4bssFB9zQsuOsdAdUEwehxqNJtkaVMB8X1yHLKb\\/R\\/VVukrXhvK2HjyMJj3puvFM3p9uigPiLgMOVBWPmNvFH7R5BQbZNUuiSius47F7+8fgYJD4BT6N9KGHQzjr6oVNWkAPFLCD9dWY4Q8QlwWhxrYIN93G5AVHoOZIwJfB222PQ+9Mv7OJwL2WC3DeVJ3Kp+0t\\/zYerBNzk0ubqL3aTaoCZolsfJ6WkeHI=\",\"authtag\":\"r9ScJzcA4lywZyOKSG7rhg==\"}";
        resp.addProperty("resp_ts",1706977101);
        resp.addProperty("resp_data",respData);

        return resp;
    }

    private static JsonObject getResp2(){
        JsonObject resp = new JsonObject();
        String respData = "{\"iv\":\"GHf4xdr40nL392pj\",\"data\":\"HVEqtUqpt6B7DviH3mK9QOWZ0EPkrM5IdM4yJ3FB\\/dLAf0VfyRwMx58xf0GV7di7wU0PDrD6jjsBKikplwMcg5is7sCMtUMhRTgdwWsDGTZb18hYQkK635WDKjM2fEJvay1bxqd0NjaodzXCT8wvOk8ar63kPDyccHrK2y7NPZJVlj55QhxYWQ69UY1jtmkaG7h8kAmQ1HMHbtRyijnM5zWAWxCzVS5RGu42VogB35wSojjKW5exXhzSkUKeCJ85kJ\\/3N9xEGaoxQzG1NuPMJEAItBqfbMXVE\\/PgWh0DIWqGvejSgxGPGNgaQxkUboe\\/54s+YTQN9TwzqNMrWDwcXXMscL79CrVk9b4hpxKCizeUClHaF9hwSTD98XI3LkjRG5ApiQa8pUoE7sZJpAWKbr\\/BExajDiTc7uXI7W6LeYU6HoUEX3dLarxnRXqiAnRz+BK+dZhLEH1bBudvhpkw9aQEKucbYfNw4dOr1kxkSH8Nr6lG89cu+nXePOvTVXbM4KoU+2VkjwMvsaQMF46bClTrUjHippIJMDPJD6t3ceCgZfqBN9Flqcod0s5ITVOxp2wFYbpwTzipn+M7SLYPsJOXSJCaAqDQuiVELmqIMV\\/oW3LhKWv7lSicL+4BQ68sq+aCYLDqV\\/DOglUVjpTQZCkfCTd1WaH\\/kpk=\",\"authtag\":\"c5VFClhgXxfVqeUDAunwdQ==\"}";
        resp.addProperty("resp_ts",1706977700);
        resp.addProperty("resp_data",respData);

        return resp;
    }
    public static void main(String[] args)  {
        JsonObject resp = getResp2();
        JsonObject ctx = getCtx();
        Object res = getRealResp(ctx,resp);
        System.out.println(res);
    }
}
