package com.zsElectric.boot.charging.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.zsElectric.boot.charging.dto.StartChargingRequestDTO;
import com.zsElectric.boot.charging.dto.StartChargingResponseVO;
import com.zsElectric.boot.charging.service.ChargingBusinessService;
import com.zsElectric.boot.business.service.ThirdPartyChargingService;
import com.zsElectric.boot.charging.vo.*;
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.electric.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@Service
@RequiredArgsConstructor
public class ChargingBusinessServiceImpl implements ChargingBusinessService {

    private final ChargingUtil chargingUtil;
    private final ThirdPartyChargingService thirdPartyChargingService;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public ApiToken queryToken() {
        try {
            QueryTokenParms queryTokenParms = new QueryTokenParms();
            queryTokenParms
                    .setOperatorID(ConnectivityConstants.OPERATOR_ID)
                    .setOperatorSecret(ConnectivityConstants.PLATFORM_OPERATOR_SECRET);

            JsonNode response = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_TOKEN, BeanUtil.beanToMap(queryTokenParms), false);
            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:
                        throw new RuntimeException("系统繁忙,此时请求方稍后重试");
                    case 4001:
                        throw new RuntimeException("签名错误");
                    case 4002:
                        throw new RuntimeException("Token错误");
                    case 4003:
                        throw new RuntimeException("参数不合法,缺少必需的示例:OperatorID、Sig、TimeStamp、Data、Seq五个参数");
                    case 4004:
                        throw new RuntimeException("请求的业务参数不合法,各接口定义自己的必须参数");
                    case 500:
                        throw new RuntimeException("系统错误");
                }
            }
            String decodeData = AESCryptoUtils.decrypt(responseParms.getData(), ConnectivityConstants.PLATFORM_DATA_SECRET,
                    ConnectivityConstants.PLATFORM_DATA_SECRET_IV);

            QueryTokenResponseData responseData = objectMapper.readValue(decodeData, QueryTokenResponseData.class);

            if (responseData.getSuccStat() == 1) {
                //0-无,1-OperatorID无效
                String failReason = "";
                if (responseData.getFailReason() == 0) {
                    failReason = "无";
                }
                if (responseData.getFailReason() == 1) {
                    failReason = "OperatorID无效";
                }
                log.error("调用第三方接口获取Token失败，失败原因: {}", failReason);
                return null;
            }
            ApiToken apiToken = new ApiToken();
            apiToken.setAccessToken(responseData.getAccessToken());
            apiToken.setTokenAvailableTime(responseData.getTokenAvailableTime());
            apiToken.setObtainTime(LocalDateTime.now());
            apiToken.setExpireTime(apiToken.getObtainTime().plusSeconds(apiToken.getTokenAvailableTime()));

            return apiToken;
        } catch (Exception e) {
            throw new RuntimeException("调用第三方接口失败", e);
        }
    }

    @Override
    public ChargingPricePolicyVO queryEquipBusinessPolicy(String equipBizSeq, String connectorID) throws JsonProcessingException {
        Map<String, Object> queryTokenParms = new HashMap<>();
        // 注意：第三方接口要求大驼峰命名
        queryTokenParms.put("EquipBizSeq", equipBizSeq);
        queryTokenParms.put("ConnectorID", connectorID);
        log.info("查询设备价格策略请求参数：{}", queryTokenParms);
        JsonNode jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_EQUIP_BUSINESS_POLICY, queryTokenParms, true);
        log.info("查询设备价格策略返回结果：{}", jsonObject);
        JsonNode responseDecode = chargingUtil.responseDecode(jsonObject);
        log.info("查询设备价格策略返回结果解密后：{}", responseDecode);
        ChargingPricePolicyVO result = objectMapper.readValue(responseDecode.toString(), ChargingPricePolicyVO.class);
        
        // 保存价格策略信息到数据库
        try {
            thirdPartyChargingService.savePricePolicyInfo(result);
        } catch (Exception e) {
            log.error("保存价格策略信息到数据库失败", e);
        }
        
        return result;
    }

    @Override
    public EquipmentAuthResponseVO queryEquipAuth(String EquipAuthSeq, String ConnectorID) throws JsonProcessingException {
        Map<String, Object> queryTokenParms = new HashMap<>();
        queryTokenParms.put("EquipAuthSeq", EquipAuthSeq);
        queryTokenParms.put("ConnectorID", ConnectorID);
        log.info("查询设备认证请求参数：{}", queryTokenParms);
        JsonNode jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_EQUIP_AUTH, queryTokenParms, true);
        log.info("查询设备认证返回结果：{}", jsonObject);
        JsonNode responseDecode = chargingUtil.responseDecode(jsonObject);
        log.info("查询设备认证返回结果解密后：{}", responseDecode);
        return objectMapper.readValue(responseDecode.toString(), EquipmentAuthResponseVO.class);
    }

    @Override
    public QueryStationsInfoVO queryStationsInfo(String LastQueryTime, Integer PageNo, Integer PageSize) throws JsonProcessingException {
        Map<String, Object> queryParms = new HashMap<>();
        queryParms.put("LastQueryTime", LastQueryTime);
        queryParms.put("PageNo", PageNo);
        queryParms.put("PageSize", PageSize);
        log.info("查询充电站信息请求参数：{}", queryParms);
        JsonNode jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_STATIONS_INFO, queryParms, true);
        log.info("查询充电站信息返回结果：{}", jsonObject);
        JsonNode responseDecode = chargingUtil.responseDecode(jsonObject);
        log.info("查询充电站信息返回结果解密后：{}", responseDecode);
        if (responseDecode == null) {
            return null;
        }
        QueryStationsInfoVO result = objectMapper.readValue(responseDecode.toString(), QueryStationsInfoVO.class);
        
        // 保存充电站信息到数据库
        try {
            thirdPartyChargingService.saveStationsInfo(result);
        } catch (Exception e) {
            log.error("保存充电站信息到数据库失败", e);
        }
        
        return result;
    }

    @Override
    public QueryStationStatusVO queryStationStatus(List<String> stationIDs) throws JsonProcessingException {
        Map<String, Object> queryParms = new HashMap<>();
        queryParms.put("StationIDs", stationIDs);
        log.info("设备接口状态查询请求参数：{}", queryParms);
        JsonNode jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_STATION_STATUS, queryParms, true);
        log.info("设备接口状态查询返回结果：{}", jsonObject);
        JsonNode responseDecode = chargingUtil.responseDecode(jsonObject);
        log.info("设备接口状态查询返回结果解密后：{}", responseDecode);
        return objectMapper.readValue(responseDecode.toString(), QueryStationStatusVO.class);
    }

    @Override
    public StartChargingResponseVO startCharging(StartChargingRequestDTO requestDTO) throws JsonProcessingException {
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(requestDTO);
        log.info("设备接口状态查询请求参数：{}", stringObjectMap);
        JsonNode jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_START_CHARGE, stringObjectMap, true);
        log.info("设备接口状态查询返回结果：{}", jsonObject);
        JsonNode responseDecode = chargingUtil.responseDecode(jsonObject);
        log.info("设备接口状态查询返回结果解密后：{}", responseDecode);
        return objectMapper.readValue(responseDecode.toString(), StartChargingResponseVO.class);
    }

    @Override
    public ChargingStatusQueryResponseVO queryChargingStatus(String StartChargeSeq) throws JsonProcessingException {
        Map<String, Object> queryParms = new HashMap<>();
        queryParms.put("StartChargeSeq", StartChargeSeq);
        log.info("查询充电订单状态请求参数：{}", queryParms);
        JsonNode jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_EQUIP_CHARGE_STATUS, queryParms, true);
        log.info("查询充电订单状态返回结果：{}", jsonObject);
        JsonNode responseDecode = chargingUtil.responseDecode(jsonObject);
        log.info("查询充电订单状态返回结果解密后：{}", responseDecode);
        return objectMapper.readValue(responseDecode.toString(), ChargingStatusQueryResponseVO.class);
    }

    @Override
    public StopChargingOperationResponseVO stopCharging(String StartChargeSeq, String ConnectorID) throws JsonProcessingException {
        Map<String, Object> queryTokenParms = new HashMap<>();
        queryTokenParms.put("StartChargeSeq", StartChargeSeq);
        queryTokenParms.put("ConnectorID", ConnectorID);
        log.info("停止充电请求参数：{}", queryTokenParms);
        JsonNode jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_STOP_CHARGE, queryTokenParms, true);
        log.info("停止充电返回结果：{}", jsonObject);
        JsonNode responseDecode = chargingUtil.responseDecode(jsonObject);
        log.info("停止充电返回结果解密后：{}", responseDecode);
        return objectMapper.readValue(responseDecode.toString(), StopChargingOperationResponseVO.class);
    }
}
