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

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.dto.ZhongtaiAppSecretDTO;
import com.friday.custody.entity.InvokeRecordEntity;
import com.friday.custody.service.basicService.impl.InvokeRecordServiceImpl;
import com.friday.custody.service.basicService.impl.PullDataFailureLogServiceImpl;
import com.friday.custody.service.trustService.zhongtai.common.ZhongTaiContants;
import com.friday.custody.utils.PullDataFailureUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.friday.custody.service.trustService.zhongtai.common.ZhongTaiContants.*;

@Slf4j
@Service
public class ZhongTaiUtils {

    @Autowired
    private InvokeRecordServiceImpl invokeRecordService;

    private RestTemplate restTemplate = new RestTemplate();

    @Autowired
    PullDataFailureLogServiceImpl pullDataFailureLogService;

    private ObjectMapper objectMapper = new ObjectMapper();

    public JSONObject sendMessage(TenantEscrowAuthorizationInfoDto tenant, String api, String paramStr, Map<String, Object> paramsMap) {
        JSONObject result = null;
        //获取token
        String token = getToken(tenant);
        String tenantAppSecret = tenant.getAppSecret();
        if (ObjectUtil.isEmpty(tenantAppSecret)){
            return result;
        }
        ZhongtaiAppSecretDTO zhongtaiAppSecretDTO = new ZhongtaiAppSecretDTO();
        try {
            zhongtaiAppSecretDTO = objectMapper.readValue(tenantAppSecret, ZhongtaiAppSecretDTO.class);
        } catch (IOException e) {
            log.error("中泰解析账密失败!", e);
        }
        String appSecret = zhongtaiAppSecretDTO.getAppSecret();

        //header参数
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        long timestamp = Calendar.getInstance().getTimeInMillis();
        String nonce = UUID.randomUUID().toString().replace("-", "");
        String sign = null;
        String errorMsg = null;
        try {
            //加密
            sign = Md5Util.md5(token + timestamp + nonce, appSecret);
        } catch (Exception e) {
            log.error("中泰加密失败！", e);
        }
        log.info("中泰: 【AUTHORITY-TOKEN】：{}, 【AUTHORITY-DATE】：{} , 【AUTHORITY-NONCE】：{}, 【AUTHORITY-SIGN】：{}", token, timestamp, nonce, sign);
        boolean flag = Md5Util.verify(token + timestamp + nonce, appSecret, sign);
        log.info("中泰MD5验证是否通过 : {}", flag);
        //组装请求头
        headers.add("AUTHORITY-TOKEN",token);
        headers.add("AUTHORITY-DATE", String.valueOf(timestamp));
        headers.add("AUTHORITY-NONCE",nonce);
        headers.add("AUTHORITY-SIGN",sign);
        //组装
        JSONObject params = new JSONObject(paramsMap);
        HttpEntity<JSONObject> request = new HttpEntity<>(params, headers);
        //拼装请求参数
        String url = HOST + api + paramStr;
        ResponseEntity<String> responseEntity = null;
        try {
            responseEntity = restTemplate.exchange(url, HttpMethod.GET, request, String.class);
        }catch (Exception e){
            log.error("调用中泰接口失败! api = {}, admin = {}, trustNo={}", url, tenant.getTenantName(), tenant.getTrustNo(), e);
            errorMsg = e.getMessage();
        }


        if (!ObjectUtils.isEmpty(responseEntity)){
            result = JSONObject.parseObject(responseEntity.getBody());
            log.info("中泰证券调用接口：{}, 请求参数：{}, 返回参数：{}", api, paramsMap, result);
            if (!ObjectUtils.isEmpty(result) && SUCCESS_CODE == result.getIntValue("code")) {
                //保存调用记录
                saveInvokeRecord(tenant, tenant.getTrustNo(), api, headers.toString(), JSON.toJSONString(paramsMap), result);
                return result;
            }
        }
        if (StringUtils.isEmpty(errorMsg)){
            errorMsg = JSONObject.toJSONString(result);
        }
        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), PullDataFailureUtil.createErrorMap(tenant.getTrustNo(), api, headers, paramStr, errorMsg));
        return result;
    }

    private String getToken(TenantEscrowAuthorizationInfoDto tenant) {
        String tenantAppSecret = tenant.getAppSecret();
        if (ObjectUtil.isEmpty(tenantAppSecret)){
            return null;
        }
        ZhongtaiAppSecretDTO zhongtaiAppSecretDTO = new ZhongtaiAppSecretDTO();
        try {
            zhongtaiAppSecretDTO = objectMapper.readValue(tenantAppSecret, ZhongtaiAppSecretDTO.class);
        } catch (IOException e) {
            log.error("获取token时, 解析账密{}失败!{}",zhongtaiAppSecretDTO, e);
        }
        String appId = zhongtaiAppSecretDTO.getAppId();
        String appKey = zhongtaiAppSecretDTO.getAppKey();
        //header参数
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //组装
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        //接口参数
        map.add("appKey",appKey);
        map.add("appId",appId);
        //构造实体对象
        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(map, headers);
        String api = ZhongTaiContants.HOST + TOKEN_URL;
        ResponseEntity<String> responseEntity = restTemplate.exchange(api, HttpMethod.POST, request, String.class);
        JSONObject result = JSONObject.parseObject(responseEntity.getBody());
        if (SUCCESS_CODE == result.getInteger("code") && JSONPath.contains(result, "$.data")){
            String token = String.valueOf(result.get("data"));
            saveInvokeRecord(tenant, tenant.getTrustNo(), TOKEN_URL, headers.toString(), JSON.toJSONString(map), result);
            return token;
        }
        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), PullDataFailureUtil.createErrorMap(tenant.getTrustNo(), api, headers, JSONObject.toJSONString(map), result));
        return null;
    }


    public static void main(String[] args) {
//        TenantEscrowAuthorizationInfoDto tenant = TenantEscrowAuthorizationInfoDto.builder()
//                .trustNo("41")
//                .tenantName("P1002894")
//                .appKey("50c61aa35b7b45d08bba27df45cbe759")
//                .appSecret("6f488d7840e9498e8426d90eeeb0f669&f02ac45e4e959fc8b13c30bb8720baa40c434738ba7233df6ce3d28fde5ea24a")
//                .build();
//        Map<String, Object> paramsMap = new HashMap<>();
//        paramsMap.put("currentpage",1);
//        paramsMap.put("row",500);
//        paramsMap.put("scdate","2022-09-01");
//        paramsMap.put("ecdate","2022-10-01");
//        String paramStr = "?currentpage=" + 1 + "&rows=" + 500 + "&sdate=2022-09-01&edate=2022-10-01";
//        Map<String, Object> stringObjectMap = sendMessage(tenant, FUND_TRADE_INFO, paramStr,paramsMap);
//        System.out.println("返回结果:" + stringObjectMap);
        String ldate = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");

        try {
            ldate = sdf.format(sdf1.parse(""));
        } catch (ParseException e) {
            log.error("证券MjAccountBalanceInfo updateDate转化格式失败！", e);
        }
    }
    public void saveInvokeRecord(TenantEscrowAuthorizationInfoDto tenant, String trustNo, String invokeType, String headers, String params, JSONObject invokeResult) {
        Date now = new Date();
        InvokeRecordEntity invokeRecordEntity = InvokeRecordEntity.builder()
                .trustNo(trustNo)
                .admin(tenant.getTenantName())
                .invokeType(invokeType)
                .reqHeader(JSON.toJSONString(headers))
                .reqParam(params)
                .invokeTime(now)
                .invokeResult(String.valueOf(invokeResult))
                .queryKey(tenant.getTenantName() + "::" + trustNo + "::" + invokeType)
                .createTime(now)
                .updateTime(now)
                .build();
        invokeRecordService.save(invokeRecordEntity);
    }
}
