package com.jsowell.thirdparty.yongchengboche.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.thirdparty.ThirdPlatformTypeEnum;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.ThirdPartyStationRelation;
import com.jsowell.pile.dto.*;
import com.jsowell.pile.service.ThirdPartyStationRelationService;
import com.jsowell.pile.thirdparty.CommonParamsDTO;
import com.jsowell.thirdparty.lianlian.service.LianLianService;
import com.jsowell.thirdparty.platform.util.Cryptos;
import com.jsowell.thirdparty.platform.util.Encodes;
import com.jsowell.thirdparty.platform.util.GBSignUtils;
import com.jsowell.thirdparty.lianlian.vo.LianLianResultVO;
import com.jsowell.thirdparty.yongchengboche.dto.YCBCGetTokenDTO;
import com.jsowell.thirdparty.yongchengboche.service.YCBCService;
import com.jsowell.thirdparty.zhongdianlian.service.ZDLService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 甬城泊车 Service
 *
 * @author Lemon
 * @Date 2023/10/30 15:44:58
 */
@Service
public class YCBCServiceImpl implements YCBCService {

    @Autowired
    private ZDLService zdlService;

    @Autowired
    private LianLianService lianLianService;

    @Autowired
    private ThirdPartyStationRelationService relationService;

    @Autowired
    private RedisCache redisCache;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());


    /**
     * 获取令牌
     * @param dto
     * @return
     */
    @Override
    public String YCBCGetToken(YCBCGetTokenDTO dto) {
        String dataSecret = dto.getDataSecret();
        String dataSecretIv = dto.getDataSecretIv();
        String operatorId = dto.getOperatorId();
        String operatorSecret = dto.getOperatorSecret();
        String urlAddress = dto.getUrlAddress();
        String signSecret = dto.getSignSecret();

        String redisKey = CacheConstants.YCBC_TOKEN_BY_OPERATORID + operatorId;
        // 先查缓存
        String token = redisCache.getCacheObject(redisKey);
        if (StringUtils.isNotBlank(token)) {
            logger.info("获取甬城泊车平台令牌，缓存中有值为：{}", token);
            return token;
        }else {
            token = "";
        }
        try {
            // 请求地址
            String requestUrl = urlAddress + "query_token";

            // 请求data
            Map<String, String> data = new HashMap<>();
            data.put("OperatorID", operatorId);
            data.put("OperatorSecret", operatorSecret);
            data.put("DataSecretIV", dataSecretIv);
            String dataJson = JSONUtil.toJsonStr(data);

            // 加密
            byte[] encryptText = Cryptos.aesEncrypt(dataJson.getBytes("UTF-8"),
                    dataSecret.getBytes(), dataSecretIv.getBytes());
            String strData = Encodes.encodeBase64(encryptText);

            Map<String, String> request = new LinkedHashMap<>();
            request.put("OperatorID", operatorId);
            request.put("Data", strData);
            request.put("TimeStamp", DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, new Date()));
            request.put("Seq", "0001");

            // 生成签名
            String sig = GBSignUtils.sign(request, signSecret);
            request.put("Portname", "wcc-pro"); // 此处是与其他获取令牌方法唯一不同之处，甬城泊车获取令牌需要添加此字段
            request.put("Sig", sig);

            String tokenRequest = JSONUtil.toJsonStr(request);

            String response = HttpUtil.post(requestUrl, tokenRequest);
            LianLianResultVO result = JSON.parseObject(response, LianLianResultVO.class);
            logger.info("获取甬城泊车令牌 result:{}", result);

            if (result.getRet() == 0) {
                // 解密data
                byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64((String) result.getData()),
                        dataSecret.getBytes(), dataSecretIv.getBytes());
                String dataStr = new String(plainText, "UTF-8");
                JSONObject resultJson = (JSONObject) JSON.parse(dataStr);
                logger.info("获取甬城泊车平台令牌 resultJson:{}", resultJson);
                int succStat = resultJson.getInteger("SuccStat");
                if (succStat != 0) {
                    logger.error("获取甬城泊车平台令牌 error:{}", result.getMsg());
                    return token;
                }
                token = resultJson.getString("AccessToken");
                logger.info("甬城泊车 token: {}", token);
                // 存入缓存
                long tokenAvailableTime = resultJson.getLong("TokenAvailableTime");
                redisCache.setCacheObject(redisKey, token, (int) tokenAvailableTime, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            logger.error("获取甬城泊车平台令牌 error:", e);
            return token;
        }
        return token;
    }

    /**
     * 生成令牌
     * @param dto
     * @return
     * @throws UnsupportedEncodingException
     */
    @Override
    public Map<String, String> generateToken(CommonParamsDTO dto) throws UnsupportedEncodingException {
        return zdlService.generateToken(dto);
    }

    /**
     * 获取充电站信息
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> queryStationsInfo(QueryStationInfoDTO dto) {
        dto.setThirdPlatformType(ThirdPlatformTypeEnum.YONG_CHENG_BO_CHE.getTypeCode());
        return zdlService.queryStationsInfo(dto);
    }


    /**
     * 设备接口状态查询
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> queryStationStatus(QueryStationInfoDTO dto) {
        return zdlService.queryStationStatus(dto);
    }

    /**
     * 设备状态变化推送
     * @param dto
     * @return
     */
    @Override
    public String notificationStationStatus(PushRealTimeInfoDTO dto) {
        return zdlService.notificationStationStatus(dto);
    }

    /**
     * 请求设备认证
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> queryEquipAuth(QueryEquipmentDTO dto) {
        return lianLianService.query_equip_auth(dto);
    }

    /**
     * 请求开始充电
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> queryStartCharge(QueryStartChargeDTO dto) {
        return lianLianService.query_start_charge(dto);
    }

    /**
     * 推送启动充电结果
     * @return
     */
    @Override
    public String pushStartChargeResult(String orderCode) {
        return lianLianService.pushStartChargeResult(orderCode);
    }

    /**
     * 查询充电状态
     * @param dto
     */
    @Override
    public Map<String, String> queryEquipChargeStatus(QueryEquipChargeStatusDTO dto) {
        return lianLianService.query_equip_charge_status(dto);
    }

    /**
     * 推送充电状态
     * @param orderCode
     * @return
     */
    @Override
    public String pushChargeStatus(String orderCode) throws UnsupportedEncodingException {
        return lianLianService.pushChargeStatus(orderCode);
    }

    /**
     * 请求停止充电
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> queryStopCharge(QueryStartChargeDTO dto) {
        return lianLianService.query_stop_charge(dto);
    }

    /**
     * 推送停止充电结果(仅在 0x19的帧类型中调用)
     * @param orderCode
     * @return
     */
    @Override
    public String pushStopChargeResult(String orderCode) {
        return lianLianService.pushStopChargeResult(orderCode);
    }

    /**
     * 推送充电订单信息
     * @param orderCode
     * @return
     */
    @Override
    public String pushChargeOrderInfo(String orderCode) {
        return lianLianService.pushChargeOrderInfo(orderCode);
    }

    /**
     * 推送充电站信息
     * @param dto
     * @return
     */
    @Override
    public String pushStationInfo(PushStationInfoDTO dto) {
        return zdlService.pushStationInfo(dto);
    }

    public String pushStationInfoV2(PushStationInfoDTO dto) {
        return zdlService.pushStationInfoV2(dto);
    }

}
