package com.zsElectric.boot.common.util.electric;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.zsElectric.boot.common.constant.ConnectivityConstants;
import com.zsElectric.boot.common.util.AESCryptoUtils;
import com.zsElectric.boot.common.util.HmacMD5Util;
import com.zsElectric.boot.common.util.OkHttpUtil;
import com.zsElectric.boot.common.util.SequenceGenUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class ChargingUtil {

    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 应用层最大重试次数（除了OkHttp层的重试）
     */
    private static final int MAX_APP_RETRY_COUNT = 2;
    
    /**
     * 重试等待时间（毫秒）
     */
    private static final long RETRY_WAIT_TIME_MS = 1000;

    @Resource
    private ElectricTokenManager tokenManager;
    @Resource
    private OkHttpUtil okHttpUtil;

    /**
     * 请求封装（带重试机制）
     * @param url 请求URL
     * @param queryParms 请求参数
     * @param tokenRequired 是否需要Token
     * @return 响应结果
     */
    public JsonNode chargingRequest(String url, Map<String,Object> queryParms, boolean tokenRequired){
        Exception lastException = null;
        
        // 应用层重试机制（除了OkHttp层的重试之外）
        for (int attempt = 0; attempt <= MAX_APP_RETRY_COUNT; attempt++) {
            try {
                if (attempt > 0) {
                    log.warn("第三方接口调用失败，正在进行第 {} 次应用层重试 - URL: {}", attempt, url);
                    // 重试前等待一段时间
                    Thread.sleep(RETRY_WAIT_TIME_MS * attempt); // 线性递增等待时间
                }
                
                return doChargingRequest(url, queryParms, tokenRequired);
                
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("重试被中断 - URL: {}", url, e);
                throw new RuntimeException("调用第三方接口被中断: " + e.getMessage(), e);
            } catch (Exception e) {
                lastException = e;
                log.error("调用第三方接口失败 - URL: {}, 第 {} 次尝试", url, attempt + 1, e);
                
                // 如果是最后一次尝试，不再重试
                if (attempt >= MAX_APP_RETRY_COUNT) {
                    break;
                }
            }
        }
        
        // 所有重试都失败
        log.error("调用第三方接口所有重试都失败 - URL: {}, 总共尝试 {} 次", url, MAX_APP_RETRY_COUNT + 1);
        if (lastException != null) {
            throw new RuntimeException("调用第三方接口失败: " + lastException.getMessage(), lastException);
        } else {
            throw new RuntimeException("调用第三方接口失败，原因未知");
        }
    }
    
    /**
     * 实际执行请求的方法
     * @param url 请求URL
     * @param queryParms 请求参数
     * @param tokenRequired 是否需要Token
     * @return 响应结果
     */
    private JsonNode doChargingRequest(String url, Map<String,Object> queryParms, boolean tokenRequired) throws Exception {
        Map<String, String> headers = new HashMap<>();
        if(tokenRequired){
            headers.put("Authorization", "Bearer " + tokenManager.getValidAccessToken());
        }
        
        RequestParmsEntity requestParms = new RequestParmsEntity();
        SequenceGenUtil.SequenceResult result = SequenceGenUtil.generate();

        requestParms.setOperatorID(ConnectivityConstants.OPERATOR_ID);
        requestParms.setData(AESCryptoUtils.encrypt(objectMapper.writeValueAsString(queryParms),ConnectivityConstants.PLATFORM_DATA_SECRET,
                        ConnectivityConstants.PLATFORM_DATA_SECRET_IV));
        requestParms.setTimeStamp(result.getTimestamp());
        requestParms .setSeq(result.getSequence());
        requestParms.setSig(HmacMD5Util.genSign(requestParms.getOperatorID(),requestParms.getData(),
                        requestParms.getTimeStamp(),
                        requestParms.getSeq(),ConnectivityConstants.PLATFORM_SIG_SECRET));

        String requestJson = objectMapper.writeValueAsString(requestParms);
        log.info("调用第三方接口，URL: {}, 请求参数: {}", url, requestJson);
        JsonNode response = okHttpUtil.doPostForm(url, requestJson, headers);

        if (Objects.isNull(response)) {
            log.error("调用第三方接口返回为空，URL: {}", url);
            throw new RuntimeException("第三方接口返回为空");
        }
        log.info("调用第三方接口成功，URL: {}, 响应: {}", url, response);
        return response;
    }

    /**
     * 响应解密
     * @param response
     * @return
     */
    public JsonNode responseDecode(JsonNode response){

        try {
            if (Objects.isNull(response)) {
                log.error("第三方接口响应数据为空");
                return null;
             }
            ResponseParmsEntity responseParms = objectMapper.readValue(response.toString(), ResponseParmsEntity.class);
            String data = responseParms.getRet() + responseParms.getMsg() + responseParms.getData();
            boolean verify = HmacMD5Util.verify(data, ConnectivityConstants.PLATFORM_SIG_SECRET, responseParms.getSig());
            if (!verify) {
                log.error("第三方接口响应数据签名验证失败");
                return null;
            }
            if (responseParms.getRet() != 0){
                switch (responseParms.getRet()) {
                    case -1:
                        log.error("系统繁忙,此时请求方稍后重试");
                        break;
                    case 4001:
                        log.error("签名错误");
                        break;
                    case 4002:
                        log.error("Token错误");
                        break;
                    case 4003:
                        log.error("参数不合法,缺少必需的示例:OperatorID、Sig、TimeStamp、Data、Seq五个参数");
                        break;
                    case 4004:
                        log.error("请求的业务参数不合法,各接口定义自己的必须参数");
                        break;
                    case 500:
                        log.error("系统错误");
                        break;
                }
            }
            String decodeData = AESCryptoUtils.decrypt(responseParms.getData(), ConnectivityConstants.PLATFORM_DATA_SECRET,
                    ConnectivityConstants.PLATFORM_DATA_SECRET_IV);
            return objectMapper.readTree(decodeData);
        }catch (Exception e){
            throw new RuntimeException("第三方接口响应发生异常", e);
        }
    }


    /**
     * 统一解密接口数据-己方响应
     * */
    public String decryptData(String data) throws Exception {
        return AESCryptoUtils.decrypt(data, ConnectivityConstants.DATA_SECRET, ConnectivityConstants.DATA_SECRET_IV);
    }

    /**
     * 统一加密接口数据-己方响应
     * */
    public String encryptData(String data) throws Exception {
        return AESCryptoUtils.encrypt(data, ConnectivityConstants.DATA_SECRET, ConnectivityConstants.DATA_SECRET_IV);
    }
}
