package com.cusc.nirvana.user.rnr.fp.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cusc.nirvana.user.rnr.fp.dto.T1CommonResponseDTO;
import com.cusc.nirvana.user.rnr.fp.dto.T1UserInfoReqDTO;
import com.cusc.nirvana.user.rnr.fp.util.AESUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Service
@Slf4j
public class VehicleT1UploadServiceImpl {

    @Value("${t1.vehicle.url:}")
    private String url;

    @Value("${t1.vehicle.appId:}")
    private String appId;

    @Value("${t1.vehicle.secret:}")
    private String secret;

    @Value("${t1.vehicle.t1InstructionKey:}")
    //此接口上传的车辆信息加密密钥由工信部下发
    private String t1InstructionKey;

    @Autowired
    @Qualifier("noBalanceRestTemplateRnrFp")
    RestTemplate noBalanceRestTemplateRnrFp;

    final String encryptCarInfo(String carInfoStr) {
        byte[] key = AESUtil.MD5(t1InstructionKey);
        //构建
        AES aes = SecureUtil.aes(key);
        //加密
        return aes.encryptHex(carInfoStr);
    }

    final String getVehicleInfo(String vin) {
        try {
            long startTime = System.currentTimeMillis();
            Map<String, Object> param = new HashMap<>();
            param.put("vin", vin);
            String bodyStr = new ObjectMapper().writeValueAsString(param);//转成json格式, 要用于签名
            String ts = String.valueOf(System.currentTimeMillis());
            //生成签名
            Map<String, String> signMap = new HashMap<>();
            signMap.put("timestamp", ts);
            signMap.put("param", bodyStr);
            signMap.put("appId", appId);

            String sign = md5Sign(signMap, secret);

            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
            requestHeaders.set("sign", sign);
            requestHeaders.set("timestamp", ts);
            requestHeaders.set("appId", appId);

            ResponseEntity<String> entity =
                    noBalanceRestTemplateRnrFp.exchange(url, HttpMethod.POST, new HttpEntity<>(bodyStr, requestHeaders),
                            String.class);
            log.info("getVehicleInfo url: {},response: {},cost: {} ms", url, entity.getBody(),
                    System.currentTimeMillis() - startTime);
            return entity.getBody();
        } catch (JsonProcessingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
            log.error("get vehicle info failed:" + vin, e);
        }

        return null;
    }

    public static String md5Sign(Map<String, String> signMap, String secret) throws NoSuchAlgorithmException {
        StringBuilder signStr = new StringBuilder();
        signMap.keySet().stream().sorted().forEach(key -> {
            if (key.equalsIgnoreCase("sign")) return;
            signStr.append(key);
            Object value = signMap.get(key);
            if (value != null) {
                signStr.append(value.toString());
            }
        });
        signStr.append(secret);
        byte[] digest = MessageDigest.getInstance("MD5").digest(signStr.toString().getBytes(StandardCharsets.UTF_8));
        return encodeAsHexString(digest).toUpperCase(Locale.ROOT);
    }

    public static String encodeAsHexString(byte[] bytes) {
        StringBuilder buf = new StringBuilder();
        int i;
        for (byte aByte : bytes) {
            i = aByte;
            if (i < 0) i = i & 255 | 256;//反码不变，复原符号位，byte转int时第8位符号位会丢失
            if (i < 16) buf.append('0');//padding with zero
            buf.append(Integer.toHexString(i));
        }
        return buf.toString();
    }
}
