package com.jsowell.thirdparty.huawei.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Maps;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
import com.jsowell.common.enums.ykc.StartModeEnum;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.*;
import com.jsowell.pile.domain.huawei.HWStationInfo;
import com.jsowell.pile.dto.*;
import com.jsowell.pile.dto.huawei.DeliverEquipBusinessDTO;
import com.jsowell.pile.dto.huawei.ReceiveDeliverDTO;
import com.jsowell.pile.dto.huawei.VinStartChargeDTO;
import com.jsowell.pile.service.*;
import com.jsowell.pile.vo.base.ThirdPartyStationRelationVO;
import com.jsowell.pile.vo.uniapp.customer.BillingPriceVO;
import com.jsowell.pile.vo.web.PileStationVO;
import com.jsowell.thirdparty.huawei.HuaWeiService;
import com.jsowell.pile.thirdparty.CommonParamsDTO;
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.platform.util.HttpRequestUtil;
import com.jsowell.thirdparty.zhongdianlian.dto.ZDLGetTokenDTO;
import com.jsowell.thirdparty.zhongdianlian.service.ZDLService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 华为 Service
 *
 * @author Lemon
 * @Date 2024/1/13 9:57:12
 */
@Service
@Slf4j
public class HuaWeiServiceImpl implements HuaWeiService {

    @Autowired
    private ZDLService zdlService;

    @Autowired
    private ThirdPartyPlatformConfigService thirdPartyPlatformConfigService;

    @Autowired
    private PileBasicInfoService pileBasicInfoService;

    @Autowired
    private PileBillingTemplateService pileBillingTemplateService;

    @Autowired
    private ThirdPartyStationRelationService thirdPartyStationRelationService;

    @Autowired
    private ThirdPartySettingInfoService thirdPartySettingInfoService;

    @Autowired
    private PileMerchantInfoService pileMerchantInfoService;

    @Autowired
    private MemberPlateNumberRelationService memberPlateNumberRelationService;

    @Autowired
    private OrderBasicInfoService orderBasicInfoService;

    @Autowired
    private PileStationInfoService pileStationInfoService;

    @Autowired
    private PileConnectorInfoService pileConnectorInfoService;

    /**
     * 获取令牌
     * @param dto
     * @return
     */
    @Override
    public String HWGetToken(ZDLGetTokenDTO dto) {
        return zdlService.ZDLGetToken(dto);
    }

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

    /**
     * 校验签名
     * @param dto
     */
    @Override
    public Map<String, String> checkoutSign(CommonParamsDTO dto) {
        return zdlService.checkoutSign(dto);
    }

    /**
     * 查询站点信息
     *
     * query_stations_info
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> queryStationsInfo(QueryStationInfoDTO dto) {
        return zdlService.queryStationsInfo(dto);
    }

    /**
     * 设备接口状态查询
     * 此接口用于批量查询设备实时状态
     *
     * query_station_status
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> queryStationStatus(QueryStationInfoDTO dto) {
        return zdlService.queryStationsInfo(dto);
    }

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

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

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

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

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

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

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

    /**
     * 推送停止充电结果
     *
     * notification_stop_charge_result
     *
     * @param orderCode
     * @return
     */
    @Override
    public String notificationStopChargeResult(String orderCode) {
        return zdlService.notificationStopChargeResult(orderCode);
    }

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

    /**
     * 请求计费策略
     *
     * request_equip_business_policy
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, String> requestEquipBusinessPolicy(QueryStartChargeDTO dto) {
        String pileConnectorCode = dto.getConnectorID();
        String equipBizSeq = dto.getEquipBizSeq();
        // 根据枪口号查询计费模板，并返回信息
        ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(dto.getOperatorId());
        if (configInfo == null) {
            return null;
        }
        // 截取桩号
        String pileSn = StringUtils.substring(pileConnectorCode, 0, 14);
        // 查询该桩的站点id
        PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn);
        // 根据桩号查询正在使用的计费模板
        List<BillingPriceVO> billingPriceVOList = pileBillingTemplateService.queryBillingPrice(String.valueOf(pileBasicInfo.getStationId()));

        JSONObject resultJson = new JSONObject();
        resultJson.put("EquipBizSeq", equipBizSeq);
        resultJson.put("ConnectorID", pileConnectorCode);
        if (CollectionUtils.isEmpty(billingPriceVOList)) {
            // 为空说明未查到该枪口的计费模板
            resultJson.put("SuccStat", 1);
            resultJson.put("FailReason", 1);
        }else {
            // 延时 500ms，异步调用 下发计费策略 接口
            CompletableFuture.runAsync(() -> {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                String result = deliverEquipBusinessPolicy(equipBizSeq, pileConnectorCode);
                log.info("华为 异步调用 下发计费策略 接口 result:{}", result);
            });

            resultJson.put("SuccStat", 0);
            resultJson.put("FailReason", 0);
        }
        // 加密
        Map<String, String> resultMap = Maps.newLinkedHashMap();
        // 加密数据
        byte[] encryptText = Cryptos.aesEncrypt(resultJson.toJSONString().getBytes(),
                configInfo.getDataSecret().getBytes(), configInfo.getDataSecretIv().getBytes());
        String encryptData = Encodes.encodeBase64(encryptText);

        resultMap.put("Data", encryptData);
        // 生成sig
        String resultSign = GBSignUtils.sign(resultMap, configInfo.getSignSecret());
        resultMap.put("Sig", resultSign);

        return resultMap;
    }

    /**
     * 下发计费策略
     * @param equipBizSeq 策略下发流水号
     * @param pileConnectorCode 枪口号
     * @return
     */
    @Override
    public String deliverEquipBusinessPolicy(String equipBizSeq, String pileConnectorCode) {
        DeliverEquipBusinessDTO params = new DeliverEquipBusinessDTO();

        // 充电业务策略信息
        List<DeliverEquipBusinessDTO
                .ChargePolicyInfo> chargePolicyInfos = new ArrayList<>();
        DeliverEquipBusinessDTO.ChargePolicyInfo chargePolicyInfo = new DeliverEquipBusinessDTO.ChargePolicyInfo();

        // 业务策略信息体
        List<DeliverEquipBusinessDTO
                .ChargePolicyInfo
                .PricePolicyInfo> pricePolicyInfos = new ArrayList<>();
        DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo pricePolicyInfo = new DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo();

        // 计费信息
        List<DeliverEquipBusinessDTO
                .ChargePolicyInfo
                .PricePolicyInfo
                .PolicyInfo> policyInfoList = new ArrayList<>();
        DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo.PolicyInfo policyInfo = null;

        // 截取桩号
        String pileSn = StringUtils.substring(pileConnectorCode, 0, 14);
        // 查询该桩的站点id
        PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn);
        String stationId = String.valueOf(pileBasicInfo.getStationId());

        // 获取运营商组织结构代码
        // MerchantInfoVO merchantInfoVO = pileMerchantInfoService.getMerchantInfoVO(String.valueOf(pileBasicInfo.getMerchantId()));
        // String organizationCode = merchantInfoVO.getOrganizationCode();

        // 通过站点id查询相关配置信息
        ThirdPartyStationRelation relation = new ThirdPartyStationRelation();
        relation.setStationId(Long.parseLong(stationId));
        ThirdPartyStationRelationVO relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation);
        if (relationInfo == null) {
            return null;
        }
        // 根据站点id查询正在使用的计费模板
        List<BillingPriceVO> billingPriceVOList = pileBillingTemplateService.queryBillingPrice(stationId);
        if (CollectionUtils.isEmpty(billingPriceVOList)) {
            return null;
        }
        for (BillingPriceVO billingPriceVO : billingPriceVOList) {
            // 将时段开始时间、电费、服务费信息进行封装
            policyInfo = new DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo.PolicyInfo();
            String startTime = billingPriceVO.getStartTime() + ":00"; // 00:00:00 格式
            // 需要将中间的冒号去掉，改为 000000 格式
            String replace = StringUtils.replace(startTime, ":", "");
            policyInfo.setStartTime(replace);
            policyInfo.setElecPrice(new BigDecimal(billingPriceVO.getElectricityPrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
            policyInfo.setSevicePrice(new BigDecimal(billingPriceVO.getServicePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));

            policyInfoList.add(policyInfo);
        }

        BillingPriceVO billingPriceVO = billingPriceVOList.get(0);
        // String equipmentOwnerId = "";
        // if (StringUtils.isNotBlank(organizationCode) && organizationCode.length() == 18) {
        //     equipmentOwnerId = StringUtils.substring(organizationCode, organizationCode.length() - 10, organizationCode.length() - 1);
        // }else {
        //     equipmentOwnerId = Constants.OPERATORID_JIANG_SU;
        // }

        // 封装参数
        pricePolicyInfo.setEquipBizID(Constants.OPERATORID_JIANG_SU + billingPriceVO.getTemplateCode()); // 计费策略ID
        pricePolicyInfo.setValidStat(1); // 执行状态
        pricePolicyInfo.setValidStartTime(billingPriceVO.getPublishTime()); // 生效时间
        pricePolicyInfo.setValidEndTime("2099-12-31 23:59:59"); // 失效时间
        pricePolicyInfo.setSumPeriod(policyInfoList.size()); // 时段数
        pricePolicyInfo.setPolicyInfos(policyInfoList);

        pricePolicyInfos.add(pricePolicyInfo);

        chargePolicyInfo.setConnectorID(pileConnectorCode);
        chargePolicyInfo.setPricePolicyInfos(pricePolicyInfos);

        chargePolicyInfos.add(chargePolicyInfo);

        params.setEquipBizSeq(equipBizSeq);
        params.setSumChargePolicyInfos(pricePolicyInfos.size());
        params.setChargePolicyInfos(chargePolicyInfos);

        String jsonString = JSON.toJSONString(params);

        // 获取请求参数
        String operatorId = relationInfo.getOperatorId();
        String operatorSecret = relationInfo.getOperatorSecret();
        String signSecret = relationInfo.getSignSecret();
        String dataSecret = relationInfo.getDataSecret();
        String dataSecretIv = relationInfo.getDataSecretIv();
        String urlAddress = relationInfo.getUrlAddress();
        String thirdPartyType = relationInfo.getThirdPartyType();

        String url = urlAddress + "deliver_equip_business_policy";
        // 获取令牌
        ZDLGetTokenDTO dto = new ZDLGetTokenDTO();
        dto.setOperatorId(operatorId);
        dto.setDataSecret(dataSecret);
        dto.setSignSecret(signSecret);
        dto.setUrlAddress(urlAddress);
        dto.setDataSecretIv(dataSecretIv);
        dto.setOperatorSecret(operatorSecret);
        String token = HWGetToken(dto);
        // 发送请求
        String result = HttpRequestUtil.sendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret);
        return result;
    }

    /**
     * 下发计费策略响应
     * 平台 <-- 华为
     * @return
     */
    @Override
    public Map<String, String> receiveDeliverEquipBusinessPolicyResult(ReceiveDeliverDTO dto) {
        ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(dto.getOperatorId());
        if (configInfo == null) {
            return null;
        }
        List<ReceiveDeliverDTO.ChargePolicyInfoRet> chargePolicyInfoRets = dto.getChargePolicyInfoRets();
        // 将下发失败的进行筛选、收集
        List<ReceiveDeliverDTO.ChargePolicyInfoRet> failedList = chargePolicyInfoRets.stream()
                .filter(x -> x.getSuccStat() == Constants.one) // 1-失败
                .collect(Collectors.toList());
        for (ReceiveDeliverDTO.ChargePolicyInfoRet chargePolicyInfoRet : failedList) {
            log.error("华为下发计费策略响应, 枪口:{} 下发计费策略失败, 失败原因:{}", chargePolicyInfoRet.getConnectorID(), chargePolicyInfoRet.getFailReason());
            // TODO 重新下发

        }
        // 返回参数
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("SuccStat", 0);
        map.put("FailReason", 0);

        // 加密
        Map<String, String> resultMap = Maps.newLinkedHashMap();
        // 加密数据
        byte[] encryptText = Cryptos.aesEncrypt(JSON.toJSONString(map).getBytes(),
                configInfo.getDataSecret().getBytes(), configInfo.getDataSecretIv().getBytes());
        String encryptData = Encodes.encodeBase64(encryptText);

        resultMap.put("Data", encryptData);
        // 生成sig
        String resultSign = GBSignUtils.sign(resultMap, configInfo.getSignSecret());
        resultMap.put("Sig", resultSign);

        return resultMap;
    }

    /**
     * vin启动充电
     * 平台 <-- 华为
     *
     * insert_start_charge
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, String> vinStartCharge(VinStartChargeDTO dto) throws Exception {
        ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(dto.getOperatorId());
        if (configInfo == null) {
            return null;
        }
        Map<String, Object> paramMap = new LinkedHashMap<>();

        String vinCode = dto.getVin();
        String pileConnectorCode = dto.getConnectorID();
        // 截取桩号、枪口号
        String pileSn = StringUtils.substring(pileConnectorCode, 0, pileConnectorCode.length() - 2);
        String connectorCode = StringUtils.substring(pileConnectorCode, pileConnectorCode.length() - 2, pileConnectorCode.length());
        // 根据vin查询小程序平台用户信息
        MemberPlateNumberRelation basicInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(vinCode);
        if (basicInfo == null) {
            // 该用户未注册
            throw new BusinessException(ReturnCodeEnum.CODE_GENERATE_ORDER_ERROR);
        }

        // 生成订单，并启动充电
        GenerateOrderDTO generateOrderDTO = new GenerateOrderDTO();
        generateOrderDTO.setMemberPlateNumberRelation(basicInfo);
        generateOrderDTO.setPileSn(pileSn);
        generateOrderDTO.setConnectorCode(connectorCode);
        generateOrderDTO.setStartMode(StartModeEnum.VIN_CODE.getValue());
        generateOrderDTO.setMemberId(basicInfo.getMemberId());
        generateOrderDTO.setStartSoc(String.valueOf(dto.getSoc()));

        int succStat = Constants.one; // 操作结果
        int failReason = Constants.one; // 失败原因
        Map<String, Object> map = orderBasicInfoService.generateOrderByCard(generateOrderDTO);
        if (map != null) {
            // 鉴权成功
            succStat = Constants.zero;
            failReason = Constants.zero;
        }
        paramMap.put("SuccStat", succStat);
        paramMap.put("FailReason", failReason);

        // 加密
        Map<String, String> resultMap = Maps.newLinkedHashMap();
        // 加密数据
        byte[] encryptText = Cryptos.aesEncrypt(JSON.toJSONString(paramMap).getBytes(),
                configInfo.getDataSecret().getBytes(), configInfo.getDataSecretIv().getBytes());
        String encryptData = Encodes.encodeBase64(encryptText);

        resultMap.put("Data", encryptData);
        // 生成sig
        String resultSign = GBSignUtils.sign(resultMap, configInfo.getSignSecret());
        resultMap.put("Sig", resultSign);

        return resultMap;
    }


    /**
     * 平台充电设备编码同步
     * @param dto
     * @return
     */
    @Override
    public String notificationOperationSystemInfo(PushStationInfoDTO dto) {
        // 通过第三方配置类型查询相关配置信息
        ThirdPartySettingInfo settingInfo = new ThirdPartySettingInfo();
        settingInfo.setType(dto.getThirdPartyType());
        ThirdPartySettingInfo thirdPartySettingInfo = thirdPartySettingInfoService.selectSettingInfo(settingInfo);
        String operatorId = thirdPartySettingInfo.getOperatorId();
        String operatorSecret = thirdPartySettingInfo.getOperatorSecret();
        String signSecret = thirdPartySettingInfo.getSignSecret();
        String dataSecret = thirdPartySettingInfo.getDataSecret();
        String dataSecretIv = thirdPartySettingInfo.getDataSecretIv();
        String urlAddress = thirdPartySettingInfo.getUrlAddress();

        List<HWStationInfo
                .EquipmentLogicInfo> equipmentLogicInfos = new ArrayList<>();

        // 通过站点id查询站点信息
        PileStationVO stationInfo = pileStationInfoService.getStationInfo(String.valueOf(dto.getStationId()));
        if (stationInfo == null) {
            return null;
        }
        HWStationInfo hwStationInfo = HWStationInfo.builder()
                .stationId(stationInfo.getId())
                .stationName(stationInfo.getStationName())

                .build();
        // 查询桩列表
        equipmentLogicInfos = getPileList(String.valueOf(dto.getStationId()));

        hwStationInfo.setEquipmentInfoNum(equipmentLogicInfos.size());
        hwStationInfo.setEquipmentLogicInfos(equipmentLogicInfos);

        String jsonString = JSON.toJSONString(hwStationInfo);

        String url = urlAddress + "notification_operation_system_info";
        // 获取令牌
        ZDLGetTokenDTO getTokenDTO = new ZDLGetTokenDTO();
        getTokenDTO.setOperatorId(operatorId);
        getTokenDTO.setDataSecret(dataSecret);
        getTokenDTO.setSignSecret(signSecret);
        getTokenDTO.setUrlAddress(urlAddress);
        getTokenDTO.setDataSecretIv(dataSecretIv);
        getTokenDTO.setOperatorSecret(operatorSecret);
        String token = HWGetToken(getTokenDTO);
        // 发送请求
        String result = HttpRequestUtil.sendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret);
        return result;

    }

    private List<HWStationInfo.EquipmentLogicInfo> getPileList(String stationId) {
        List<HWStationInfo
                .EquipmentLogicInfo> equipmentLogicInfos = new ArrayList<>();
        HWStationInfo
                .EquipmentLogicInfo equipmentLogicInfo = null;

        List<PileBasicInfo> pileBasicInfos = pileBasicInfoService.getPileListByStationId(stationId);
        if (CollectionUtils.isEmpty(pileBasicInfos)) {
            return new ArrayList<>();
        }
        for (PileBasicInfo pileBasicInfo : pileBasicInfos) {
            String pileSn = pileBasicInfo.getSn();
            equipmentLogicInfo = HWStationInfo.EquipmentLogicInfo.builder()
                    .equipmentId(pileSn)
                    // .equipmentType()
                    .chargeHostESN(pileSn)
                    .build();
            // 获取枪口信息
            List<HWStationInfo.EquipmentLogicInfo
                    .ConnectorInfo> connectorInfoList = getConnectorInfoList(pileSn);
            if (CollectionUtils.isEmpty(connectorInfoList)) {
                continue;
            }
            equipmentLogicInfo.setConnectorInfoNum(connectorInfoList.size());
            equipmentLogicInfo.setConnectorInfos(connectorInfoList);

            equipmentLogicInfos.add(equipmentLogicInfo);
        }
        return equipmentLogicInfos;
    }

    private List<HWStationInfo.EquipmentLogicInfo.ConnectorInfo> getConnectorInfoList(String pileSn) {
        List<HWStationInfo.EquipmentLogicInfo
                .ConnectorInfo> connectorInfoList = new ArrayList<>();
        HWStationInfo.EquipmentLogicInfo
                .ConnectorInfo connectorInfo = null;

        List<PileConnectorInfo> pileConnectorInfos = pileConnectorInfoService.selectPileConnectorInfoList(pileSn);
        if (CollectionUtils.isEmpty(pileConnectorInfos)) {
            return new ArrayList<>();
        }
        for (PileConnectorInfo pileConnectorInfo : pileConnectorInfos) {
            connectorInfo = HWStationInfo.EquipmentLogicInfo.ConnectorInfo.builder()
                    .connectorID(pileConnectorInfo.getPileConnectorCode())
                    .connectorNumber(pileConnectorInfo.getId())

                    .build();
            connectorInfoList.add(connectorInfo);
        }
        return connectorInfoList;
    }

}
