package com.friday.custody.service.trustService.swhy.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.friday.custody.dto.SWAppSecretDTO;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.entity.InvokeRecordEntity;
import com.friday.custody.service.basicService.InvokeRecordService;
import com.friday.custody.service.basicService.PullDataFailureLogService;
import com.friday.custody.service.trustService.swhy.common.HttpClientCall;
import com.friday.custody.service.trustService.swhy.common.Param;
import com.friday.custody.utils.PullDataFailureUtil;
import com.swhy.api.AESUtils;
import com.swhy.api.HmacUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service("sWHYUtils")
public class SWHYUtils {
    @Autowired
    private InvokeRecordService invokeRecordService;

    @Autowired
    private PullDataFailureLogService pullDataFailureLogService;

    private ObjectMapper objectMapper = new ObjectMapper();

    public Map<String, Object> call(String url, String params, TenantEscrowAuthorizationInfoDto tenant) throws Exception {
        String tenantAppSecret = tenant.getAppSecret();
        SWAppSecretDTO swAppSecretDTO = new SWAppSecretDTO();
        try {
            swAppSecretDTO = objectMapper.readValue(tenantAppSecret, SWAppSecretDTO.class);
        } catch (IOException e) {
            log.error("解析托管账密{}失败!{}", e, swAppSecretDTO);
        }
        //AES密钥
        String AES_appSecret = swAppSecretDTO.getAesAppSecret();
        //HAMC密钥
        String HMAC_appSecret = swAppSecretDTO.getHmacAppSecret();
        //时间戳
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String timeStamp = df.format(new Date());
        //管理人备案编码
        String managerId = swAppSecretDTO.getManagerId();
        //1 AES加密测试报文
        String bizParam = AESUtils.URLEncode(params, AES_appSecret);
        //2 按ASCII码从小到大排序参数
        String appsigned = "bizParam=" + bizParam + "&managerId" + managerId + "&timeStamp" + timeStamp;
        log.info("appsigned:" + appsigned);
        //3 签名
        appsigned = HmacUtils.signHMAC(appsigned, HMAC_appSecret);
        log.info("appsigned-->after:" + appsigned);
        //4.封装参数到Map
        Map<String, String> bizParams = new HashMap<String, String>();
        bizParams.put("managerId", managerId);
        bizParams.put("timeStamp", timeStamp);
        bizParams.put("bizParam", bizParam);
        bizParams.put("appsigned", appsigned);
        //5.调用平台相关接口，本例使用HttpClient的POST方式
        HttpClientCall call = new HttpClientCall();
        Param param = new Param(bizParams);
        String info = call.call(param, url, "");
        //6.拿到返回报文
        System.out.println("info" + info);
        //7.解密
        Map mapData = new HashMap();
        try {
            String str2 = AESUtils.URLDecode(info, AES_appSecret);
            mapData = JSONObject.parseObject(str2, Map.class);
            if (mapData == null) {
                mapData = new HashMap();
            }
            log.info("申万：{}调用{}接口, 返回数据：{}", tenant, url, mapData);

            //判断接口返回数据
            if ("0000".equals(mapData.get("retCode"))) {
                saveInvokeRecord(tenant, tenant.getTrustNo(), url, "", params, mapData);
                //接口有分页和无分页返回结构不同，加一个Boolean用来判断
                mapData.put("result", true);
                return mapData;
            } else {
                log.info("获取申万数据失败");
                pullDataFailureLogService.saveErrorData(tenant.getTenantName(),
                        PullDataFailureUtil.createErrorMap(tenant.getTrustNo(), url, "", "appKey="+ managerId + "&params=" + param, mapData ));
            }
        } catch (Exception e) {
            log.error("解析申万结果数据异常", e);
            pullDataFailureLogService.saveErrorData(tenant.getTenantName(),
                    PullDataFailureUtil.createErrorMap(tenant.getTrustNo(), url, "", "appKey="+ managerId + "&params=" + param, info ));
        }
        mapData.put("result", false);
        return mapData;
    }

    public void saveInvokeRecord(TenantEscrowAuthorizationInfoDto tenant, String trustNo, String invokeType, String headers, String params, Map invokeResult) {
        Date now = new Date();
        InvokeRecordEntity invokeRecordEntity = InvokeRecordEntity.builder()
                .trustNo(trustNo)
                .admin(tenant.getTenantName())
                .invokeType(invokeType)
                .reqHeader(JSON.toJSONString(headers))
                .reqParam(JSON.toJSONString(params))
                .invokeTime(now)
                .invokeResult(JSON.toJSONString(invokeResult))
                .queryKey(tenant.getTenantName() + "::" + trustNo + "::" + invokeType)
                .createTime(now)
                .updateTime(now)
                .build();
        invokeRecordService.save(invokeRecordEntity);
    }
}
