package cn.pluss.platform.ys.impl.v20220527;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.DES;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.util.*;
import cn.pluss.platform.ys.YsConfig;
import cn.pluss.platform.ys.YsOldConfig;
import cn.pluss.platform.ys.impl.v20210929.YsConfigV2;
import cn.pluss.platform.ys.impl.v20210929.YsConstant;
import cn.pluss.platform.ys.impl.v20220527.entity.Meta;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@Service("ysServiceV3")
public class YsServiceV3 {
    @Autowired
    private YsConfig ysConfig;
    @Autowired
    private RestTemplate restTemplate;
    @Resource
    private YsConfigV3 ysConfigV3;
    /**
     * 只用于新的进件接口
     *
     * @param reqMethod 请求方法
     * @param reqData   请求参数
     * @return
     */
    public RespEntity req(ReqMethod reqMethod, JSONObject reqData, Integer channel) {
        Calendar calendar = Calendar.getInstance();
        int i = calendar.get(Calendar.HOUR_OF_DAY);

        if (i < 8 || i >= 21) {
            throw new MsgException("当前时段暂不支持入网，请于8:00-21:00提交");
        }
        String key = RandomUtil.randomString(RandomUtil.BASE_NUMBER + "ABCDEF",16);
        try {
            ReqEntity request = ReqEntity.get(reqMethod);
            Sign sign = null;
            if (channel.equals(4)) {
                request.setCertId(ysConfig.getSrcMerchantNo());
                RSA rsa = SecureUtil.rsa(ysConfig.getPriKey(), ysConfig.getOldPubKey());
                request.setCheck(rsa.encryptBase64(key, KeyType.PublicKey));
                sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, ysConfig.getPriKey(), ysConfig.getOldPubKey());
            }else {
                request.setCertId(ysConfigV3.getSrcMerchantNoD1());
                RSA rsa = SecureUtil.rsa(ysConfigV3.getPriKeyV2D1(), ysConfigV3.getPubKeyV2D1());
                request.setCheck(rsa.encryptBase64(key, KeyType.PublicKey));
                sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, ysConfigV3.getPriKeyV2D1(), ysConfigV3.getPubKeyV2D1());
            }
            request.setBizContent(reqData.toJSONString());
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            headers.add("User-Agent",
                    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36");

            log.info("业务参数==============>" + JSONObject.toJSONString(reqData));

            log.info("key = " + key);
            AES aes = new AES(key.getBytes(StandardCharsets.UTF_8));
            String s = aes.encryptBase64(request.getBizContent());
            request.setBizContent(s);

            String encryptOriginData = SignUtils.getSignContent((JSONObject) JSON.toJSON(request));

            log.info("加签源数据==============>" + encryptOriginData);
            request.setSign(Base64.encode(sign.sign(encryptOriginData)));
            log.warn("请求报文==============>" + JSONObject.toJSONString(request));
            log.info("请求地址：{}", reqMethod.getUrl());

            HttpEntity<JSONObject> reqEntity = new HttpEntity<>((JSONObject) JSON.toJSON(request), headers);
            String respStr = restTemplate.postForObject(reqMethod.getUrl(), reqEntity, String.class);
            log.info("返回信息base64：{}", respStr);
            byte[] decode = Base64.decode(respStr);
            respStr = new String(decode, StandardCharsets.UTF_8);
            log.info("返回信息：{}", respStr);

            JSONObject param = JSON.parseObject(respStr);
            String signContent = SignUtils.getSignContent(param);
            System.out.println("加签原参数：" + signContent);

            boolean checkSign;
            try {
                checkSign = sign.verify(signContent.getBytes(StandardCharsets.UTF_8), Base64.decode(param.getString("sign")));
            } catch (Exception e) {
                log.error("银盛云商服3.0接口验签失败{}", e.getMessage());
                e.printStackTrace();
                checkSign = true;
            }

            if (!checkSign) {
                throw new MsgException("银盛云商服3.0接口验签不通过");
            }

            RespEntity respEntity = JSON.parseObject(respStr, RespEntity.class);

            // 检查网关code码
            if (!Objects.equals(respEntity.getCode(), YsConfigV3.REQ_SUCCESS)) {
                throw new MsgException(respEntity.getMsg());
            }

            // 业务响应码这里不做判断，交给具体接口业务逻辑去判断
            if (StringUtils.hasText(respEntity.getBusinessData())) {
                byte[] bizBytes = Base64.decode(respEntity.getBusinessData());
                String decryptBizData = aes.decryptStr(bizBytes);
                respEntity.setBusinessData(decryptBizData);
                log.info("业务参数: {}", respEntity.getBusinessData());
            }

            return respEntity;
        } catch (Exception e) {
            if (e instanceof MsgException) {
                throw e;
            }

            return null;
        }
    }

    public RespEntity reqUpload(ReqMethod reqMethod, String picType, String fileUrl, String sysFlowId) {
        Calendar calendar = Calendar.getInstance();
        int i = calendar.get(Calendar.HOUR_OF_DAY);

        if (i < 8 || i >= 21) {
            throw new MsgException("当前时段暂不支持入网，请于8:00-21:00提交");
        }

        Meta meta = new Meta();
        meta.setPicType(picType);
        meta.setSysFlowId(sysFlowId);
        meta.setChangeFlowId(sysFlowId);
        try {
            ReqEntity request = ReqEntity.get(ReqMethod.upload);
            request.setCertId(ysConfig.getSrcMerchantNo());

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            headers.add("User-Agent",
                    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36");

            MultiValueMap<String, Object> reqMap = new LinkedMultiValueMap<>();
            try {
                String imgBase64Data = FileUtil.getBase64FromUrl(fileUrl);
                String compressPic = Base64Util.compressPic(imgBase64Data, 1024);
                byte[] byteArray = Base64.decode(compressPic);
                ByteArrayResource file = new ByteArrayResource(byteArray) {
                    @Override
                    public String getFilename() {
                        return "test.jpg";
                    }
                };
                reqMap.add("file", file);
                String sha256 = DigestUtil.sha256Hex(file.getInputStream());
                meta.setSha256(sha256);
                meta.setPicNm("test.jpg");
            } catch (IOException e) {
                e.printStackTrace();
            }

            JSONObject reqData = new JSONObject();
            reqData.put("meta", meta);
            request.setBizContent(reqData.toString());

            log.info("业务参数==============>" + reqData);
            String key = RandomUtil.randomString(RandomUtil.BASE_NUMBER + "ABCDEF",16);
            log.info("key = " + key);
            AES aes = new AES(key.getBytes(StandardCharsets.UTF_8));
            String s = aes.encryptBase64(request.getBizContent());
            request.setBizContent(s);

            RSA rsa = SecureUtil.rsa(ysConfig.getPriKey(), ysConfig.getOldPubKey());
            request.setCheck(rsa.encryptBase64(key, KeyType.PublicKey));

            String encryptOriginData = SignUtils.getSignContent((JSONObject) JSON.toJSON(request));
            Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, ysConfig.getPriKey(), ysConfig.getOldPubKey());
            log.info("加签源数据==============>" + encryptOriginData);
            request.setSign(Base64.encode(sign.sign(encryptOriginData)));

            reqMap.addAll(MapUtils.map2MultiValueMap((JSONObject) JSON.toJSON(request)));
            HttpEntity<MultiValueMap<String, Object>> reqEntity = new HttpEntity<>(reqMap, headers);

            String respStr = restTemplate.postForObject(reqMethod.getUrl(), reqEntity, String.class);
            log.info("返回信息base64：{}", respStr);
            byte[] decode = Base64.decode(respStr);
            respStr = new String(decode, StandardCharsets.UTF_8);
            log.info("返回信息：{}", respStr);

            JSONObject param = JSON.parseObject(respStr);
            String signContent = SignUtils.getSignContent(param);
            System.out.println("加签原参数：" + signContent);

            boolean checkSign;
            try {
                checkSign = sign.verify(signContent.getBytes(StandardCharsets.UTF_8), Base64.decode(param.getString("sign")));
            } catch (Exception e) {
                log.error("银盛云商服3.0图片上传接口验签失败: {}",  e.getMessage());
                e.printStackTrace();
                checkSign = true;
            }

            if (!checkSign) {
                throw new MsgException("银盛云商服3.0接口验签不通过");
            }

            RespEntity respEntity = JSON.parseObject(respStr, RespEntity.class);

            // 检查网关code码
            if (!Objects.equals(respEntity.getCode(), YsConfigV3.REQ_SUCCESS)) {
                throw new MsgException(respEntity.getMsg());
            }

            // 业务响应码这里不做判断，交给具体接口业务逻辑去判断

            if (respEntity.getBusinessData() != null) {
                byte[] bizBytes = Base64.decode(respEntity.getBusinessData());
                String decryptBizData = aes.decryptStr(bizBytes);
                respEntity.setBusinessData(decryptBizData);
            }

            log.info("业务返回参数: {}", respEntity.getBusinessData());

            return respEntity;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
