package com.zxw.util.tm;

import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONObject;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.*;

/**
 * 天迈数据http请求
 */
public class HttpTmEncryptUtil {
    /**
     * 客户端appid
     */
    private static String appId = "1924051882771222530";
    /**
     * 客户端鉴权密钥
     */
    private static String secret = "869v5NED";
    /**
     * 数据加密密钥
     */
    private static String secretKey = "...";

    /**
     * 天迈数据请求地址
     */
    private static final String TM_PERSON_DATA_URL = "http://10.100.102.67:22220/api/basis/deptInfoExtRepair";

    // 示例调用
    public static void main(String[] args) {
        // 构造请求参数
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
//        params.add("dataDate", "20250301");
//        params.add("curPage", "1");
//        params.add("pageSize", "10");

        JSONObject boby = new JSONObject();
        boby.append("curPage", "1");
        boby.append("pageSize", "1");

        // 构造请求体（JSON）
//        String body = "{\"dataDate\":\"20250301\"}";

        // 发送请求
        String response = sendPostRequest(TM_PERSON_DATA_URL, params, boby.toString());
        System.out.println("响应结果: " + response);
    }

    /**
     * 构建带有鉴权头的POST请求
     */
    public static String sendPostRequest(String url, MultiValueMap<String, String> params, String body) {
        RestTemplate restTemplate = new RestTemplate();
        try {
            // 1. 生成鉴权头
            HttpHeaders headers = getHeaders(params, body);
            // 2. 构建请求实体（包含头和体）
            HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
            // 3. 发送POST请求
            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                String.class
            );
            return response.getBody();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("编码错误", e);
        }
    }

    /**
     * 拼装请求数据
     *
     * @param appid     appid
     * @param timestamp 时间戳
     * @param params   参数
     * @param body      请求体
     */
    public static String baseString(String appid, long timestamp, MultiValueMap<String, String> params, @Nullable String body) throws UnsupportedEncodingException {
        StringBuilder baseString = new StringBuilder();
        if (MapUtils.isNotEmpty(params)) {
            params.keySet().stream().sorted().forEach(key -> {
                List<String> values = params.get(key);
                if (CollectionUtils.isNotEmpty(values)) {
                    baseString.append(key).append("=");
                    baseString.append(values.size() == 1 ? values.get(0) : Arrays.toString(values.toArray()));
                    baseString.append("&");
                }
            });
        }
        baseString.append("appid=").append(appid).append("&");
        baseString.append("timestamp=").append(timestamp);
        if (StringUtils.isNotBlank(body)) {
            body = body.replaceAll("\\s*", StringUtils.EMPTY);
            baseString.append("&body=").append(body);
        }

        return URLDecoder.decode(baseString.toString(), StandardCharsets.UTF_8.name());
    }

    /**
     * 生成摘要digest
     *
     * @param secret secret
     * @param salt   拼接好的请求参数字符串
     */
    public static String encode(String secret , String salt) {
        final byte[] key = secret .getBytes(StandardCharsets.UTF_8);
        final byte[] digest = salt.getBytes(StandardCharsets.UTF_8);
        byte[] bytes = HmacUtils.hmacSha1(key, digest);
        return Base64.encode(bytes);
    }

    /**
     * 获取鉴权Authorization
     *
     * @param timestamp 当前请求时间戳
     * @param params    请求url参数
     * @param body      请求体
     * @return 鉴权Authorization
     */
    private static String getAuthorization(long timestamp, MultiValueMap<String, String> params, String body) throws UnsupportedEncodingException {
        String salt = baseString(appId, timestamp, params, body);
        return "HmacSHA " + appId + ":" + timestamp + ":" + encode(secret , salt);
    }

    /**
     * 获取设置鉴权的HttpHeaders
     *
     * @param params 请求url参数
     * @param body   请求体
     * @return HttpHeaders
     */
    private static HttpHeaders getHeaders(MultiValueMap<String, String> params, String body) throws UnsupportedEncodingException {
        // 当前请求时间戳
        long timestamp = System.currentTimeMillis();
        String authorization = getAuthorization(timestamp, params, body);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.set("Content-Type", "application/json");
        httpHeaders.set("Authorization", authorization);
        System.out.println(authorization);
        return httpHeaders;
    }


    /**
     * 解密
     * @param result 返回数据(AES加密后的)
     * @return 解密数据
     */
    protected String decrypt(String result) throws Exception {
        // 将接口返回的加密数据使用BASE64算法解码
        byte[] datas = new BASE64Decoder().decodeBuffer(result);

        // 使用AES/ECB/PKCS5Padding解密算法
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

        // 使用服务端发放的128位解密密钥secretKey
        Key key = new SecretKeySpec(secretKey.getBytes(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, key);

        //解密
        byte[] bytes = cipher.doFinal(datas);

        // 将解密的字节数组转出字符串使用
        return new String(bytes, StandardCharsets.UTF_8);
    }
}
