package com.jsowell.thirdparty.service.impl;

import cn.hutool.core.util.PageUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.common.enums.lianlian.LianLianPileStatusEnum;
import com.jsowell.common.enums.lianlian.PayChannelEnum;
import com.jsowell.common.enums.lianlian.StationPaymentEnum;
import com.jsowell.common.enums.ykc.*;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.*;
import com.jsowell.common.util.lianlian.*;
import com.jsowell.netty.command.ykc.StartChargingCommand;
import com.jsowell.netty.command.ykc.StopChargingCommand;
import com.jsowell.netty.service.yunkuaichong.YKCPushCommandService;
import com.jsowell.pile.domain.*;
import com.jsowell.pile.dto.*;
import com.jsowell.pile.service.*;
import com.jsowell.pile.vo.base.ConnectorInfoVO;
import com.jsowell.pile.vo.base.MerchantInfoVO;
import com.jsowell.pile.vo.lianlian.AccumulativeInfoVO;
import com.jsowell.pile.vo.uniapp.BillingPriceVO;
import com.jsowell.pile.vo.web.PileConnectorInfoVO;
import com.jsowell.pile.vo.web.PileModelInfoVO;
import com.jsowell.thirdparty.domain.*;
import com.jsowell.thirdparty.service.LianLianService;
import com.jsowell.thirdparty.vo.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class LianLianServiceImpl implements LianLianService {
	private static final String TEST_URL = "http://testdataexchange.evchargeonline.com:82/shevcs/v1/";
	private static final String OPERATOR_ID = "987654321";
	private static final String OPERATOR_SECRET = "1234567890abcdef";
	private static final String SIG_SECRET = "1234567890abcdef";              // 签名秘钥
	private static final String DATA_SECRET = "1234567890abcdef";           // 消息密钥
	private static final String DATA_SECRETIV = "1234567890abcdef";        // 消息密钥初始化向量

	@Autowired
	private IPileMerchantInfoService pileMerchantInfoService;

	@Autowired
	private IPileStationInfoService pileStationInfoService;

	@Autowired
	private IPileBasicInfoService pileBasicInfoService;

	@Autowired
	private IPileModelInfoService pileModelInfoService;

	@Autowired
	private IPileConnectorInfoService pileConnectorInfoService;

	@Autowired
	private IOrderBasicInfoService orderBasicInfoService;

	@Autowired
	private YKCPushCommandService ykcPushCommandService;

	@Autowired
	private IPileBillingTemplateService pileBillingTemplateService;

	@Override
	public void pushMerchantInfo(Long merchantId) {
		// 通过id查询运营商信息
		MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(String.valueOf(merchantId));
		// 组装联联平台所需要的数据格式
		OperatorInfo operatorInfo = OperatorInfo.builder()
				.OperatorID(Constants.OPERATORID_LIANLIAN) // 组织机构代码
				.OperatorName(merchantInfo.getMerchantName()) // 机构全称
				.OperatorTel1(merchantInfo.getMerchantTel()) // 对接平台客服电话1
				.build();
		// 调用联联平台接口


	}

	/**
	 * 根据站点id推送站点信息
	 * @param dto
	 */
	@Override
	public void pushStationInfo(LianLianPushStationInfoDTO dto){
		// String OperatorID = "987654321";
		// String SigSecret = "1234567890abcdef";              // 签名秘钥
		// String DataSecret = "1234567890abcdef";           // 消息密钥
		// String DataSecretIV = "1234567890abcdef";        // 消息密钥初始化向量
		// String token = "c548f9276c1c4ea8b88b1f7b1eb7cf07";   //QueryToken类查询接口获取到的token

		// 通过id查询站点相关信息
		PileStationInfo pileStationInfo = pileStationInfoService.selectPileStationInfoById(dto.getStationId());
		// 组装联联平台所需要的数据格式
		StationInfo info = StationInfo.builder()
				.stationID(String.valueOf(dto.getStationId()))
				.operatorID(dto.getOperatorID())
				.equipmentOwnerID(Constants.OPERATORID_LIANLIAN)
				.stationName(pileStationInfo.getStationName())
				.isAloneApply(Integer.valueOf(pileStationInfo.getAloneApply()))
				.isPublicParkingLot(Integer.valueOf(pileStationInfo.getPublicParking()))
				.countryCode(pileStationInfo.getCountryCode())
				.areaCode(pileStationInfo.getAreaCode())
				.address(pileStationInfo.getAddress())
				.serviceTel(pileStationInfo.getStationTel())
				.stationType(Integer.valueOf(pileStationInfo.getStationType()))
				.stationStatus(Integer.valueOf(pileStationInfo.getStationStatus()))
				.parkNums(Integer.valueOf(pileStationInfo.getParkNums()))
				.stationLng(new BigDecimal(pileStationInfo.getStationLng()))
				.stationLat(new BigDecimal(pileStationInfo.getStationLat()))
				.construction(Integer.valueOf(pileStationInfo.getConstruction()))
				.openAllDay(Integer.valueOf(pileStationInfo.getOpenAllDay()))
				.minElectricityPrice(new BigDecimal(Constants.ZERO))
				.electricityFee(Constants.ZERO)
				.serviceFee(Constants.ZERO)
				.parkFree(Integer.valueOf(pileStationInfo.getParkFree()))
				// .ParkFee("2")
				// .payment("线上")
				.supportOrder(Integer.valueOf(pileStationInfo.getSupportOrder()))
				// .equipmentInfos()
				.parkFeeType(0)
				.toiletFlag(Integer.valueOf(pileStationInfo.getToiletFlag()))
				.storeFlag(Integer.valueOf(pileStationInfo.getStoreFlag()))
				.restaurantFlag(Integer.valueOf(pileStationInfo.getRestaurantFlag()))
				.loungeFlag(Integer.valueOf(pileStationInfo.getLoungeFlag()))
				.canopyFlag(Integer.valueOf(pileStationInfo.getCanopyFlag()))
				.printerFlag(Integer.valueOf(pileStationInfo.getPrinterFlag()))
				.barrierFlag(Integer.valueOf(pileStationInfo.getBarrierFlag()))
				.parkingLockFlag(Integer.valueOf(pileStationInfo.getParkingLockFlag()))

				.build();
		String payment = StationPaymentEnum.getPaymentByCode(pileStationInfo.getPayment());
		info.setPayment(payment);
		List<EquipmentInfo> pileList = getPileList(pileStationInfo);
		if (CollectionUtils.isNotEmpty(pileList)) {
			info.setEquipmentInfos(pileList); // 充电设备信息列表
		}

		// 调用联联平台接口
		String url = TEST_URL + "notification_stationInfo";

		String jsonStr = JSONObject.toJSONString(info);
		JSONObject data = new JSONObject();
		data.put("StationInfo", jsonStr);

		String jsonString = JSONObject.toJSONString(data);
		System.out.println("jsonString : " + jsonString);

		String result = HttpRequestUtil.sendPost(dto.getToken(), jsonString, url, dto.getDataSecret()
				, dto.getDataSecretIV(), dto.getOperatorID(), dto.getSigSecret());

		System.out.println(result);

	}

	public static void main(String[] args){

	}

	/**
	 * 查询充电站信息
	 * 对外接口 query_stations_info
	 * @return
	 */
	@Override
	public LianLianPageResponse query_stations_info(QueryStationInfoDTO dto) {
		List<StationInfo> resultList = new ArrayList<>();
		int pageNo = dto.getPageNo() == null ? 1 : dto.getPageNo();
		int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize();

		PageUtils.startPage(pageNo, pageSize);
		List<PileStationInfo> stationInfos = pileStationInfoService.getStationInfoForLianLian();
		if (CollectionUtils.isEmpty(stationInfos)) {
			// 未查到数据
			return null;
		}
		PageInfo<PileStationInfo> pageInfo = new PageInfo<>(stationInfos);
		for (PileStationInfo pileStationInfo : pageInfo.getList()) {
			StationInfo stationInfo = new StationInfo();
			stationInfo.setStationID(String.valueOf(pileStationInfo.getId()));
			// MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(String.valueOf(pileStationInfo.getMerchantId()));
			stationInfo.setOperatorID(Constants.OPERATORID_LIANLIAN); // 组织机构代码
			stationInfo.setEquipmentOwnerID(String.valueOf(pileStationInfo.getMerchantId()));
			stationInfo.setStationName(pileStationInfo.getStationName());
			stationInfo.setIsAloneApply(Integer.valueOf(pileStationInfo.getAloneApply()));
			stationInfo.setIsPublicParkingLot(Integer.valueOf(pileStationInfo.getPublicParking()));
			stationInfo.setCountryCode(pileStationInfo.getCountryCode());
			stationInfo.setAreaCode(pileStationInfo.getAreaCode());
			stationInfo.setAddress(pileStationInfo.getAddress());
			stationInfo.setServiceTel(pileStationInfo.getStationTel());
			stationInfo.setStationType(Integer.valueOf(pileStationInfo.getStationType()));
			stationInfo.setParkNums(Integer.valueOf(pileStationInfo.getParkNums()));
			stationInfo.setStationLng(new BigDecimal(pileStationInfo.getStationLng()));
			stationInfo.setStationLat(new BigDecimal(pileStationInfo.getStationLat()));
			stationInfo.setConstruction(Integer.valueOf(pileStationInfo.getConstruction()));
			stationInfo.setOpenAllDay(Integer.valueOf(pileStationInfo.getOpenAllDay()));
			// stationInfo.setMinElectricityPrice(pileStationInfo); // 最低充电电费率
			// stationInfo.setElectricityFee(); // 电费 xx元/度
			// stationInfo.setServiceFee(); // 服务费 xx元/度
			stationInfo.setParkFree(Integer.valueOf(pileStationInfo.getParkFree()));
			stationInfo.setPayment(pileStationInfo.getPayment());
			stationInfo.setSupportOrder(Integer.valueOf(pileStationInfo.getSupportOrder()));
			// stationInfo.setParkFeeType(pileStationInfo); // 停车收费类型
			stationInfo.setToiletFlag(Integer.valueOf(pileStationInfo.getToiletFlag()));
			stationInfo.setStoreFlag(Integer.valueOf(pileStationInfo.getStoreFlag()));
			stationInfo.setRestaurantFlag(Integer.valueOf(pileStationInfo.getRestaurantFlag()));
			stationInfo.setLoungeFlag(Integer.valueOf(pileStationInfo.getLoungeFlag()));
			stationInfo.setCanopyFlag(Integer.valueOf(pileStationInfo.getCanopyFlag()));
			stationInfo.setPrinterFlag(Integer.valueOf(pileStationInfo.getPrinterFlag()));
			stationInfo.setBarrierFlag(Integer.valueOf(pileStationInfo.getBarrierFlag()));
			stationInfo.setParkingLockFlag(Integer.valueOf(pileStationInfo.getParkingLockFlag()));

			List<EquipmentInfo> pileList = getPileList(pileStationInfo);
			if (CollectionUtils.isNotEmpty(pileList)) {
				stationInfo.setEquipmentInfos(pileList); // 充电设备信息列表
			}

			resultList.add(stationInfo);
		}

		LianLianPageResponse pageResponse = LianLianPageResponse.builder()
				.PageNo(pageInfo.getPageNum())
				.PageCount(pageInfo.getPages())
				.ItemSize(resultList.size())
				.list(resultList)
				.build();
		return pageResponse;
	}

	@Override
	public LianLianPageResponse query_station_status(List<String> StationIDs) {
		List<StationStatusInfo> StationStatusInfos = new ArrayList<>();
		List<Object> ConnectorStatusInfos = new ArrayList<>();

		for (String stationId : StationIDs) {
			// 根据站点id查询
			List<ConnectorInfoVO> list = pileConnectorInfoService.getConnectorListForLianLian(Long.parseLong(stationId));
			for (ConnectorInfoVO connectorInfoVO : list) {

				String connectorStatus = connectorInfoVO.getConnectorStatus();
				if (StringUtils.equals(connectorStatus, PileConnectorDataBaseStatusEnum.OCCUPIED_CHARGING.getValue())) {
					// 充电中
					ConnectorChargeStatusInfo info = new ConnectorChargeStatusInfo();
					OrderBasicInfo orderBasicInfo = orderBasicInfoService.queryChargingByPileConnectorCode(connectorInfoVO.getPileConnectorCode());
					List<RealTimeMonitorData> chargingRealTimeData = orderBasicInfoService.getChargingRealTimeData(orderBasicInfo.getOrderCode());
					RealTimeMonitorData realTimeMonitorData = chargingRealTimeData.get(0);

					info.setStartChargeSeq(orderBasicInfo.getOrderCode());
					info.setConnectorID(orderBasicInfo.getPileConnectorCode());
					info.setConnectorStatus(Integer.valueOf(connectorInfoVO.getConnectorStatus()));
					info.setCurrentA(new BigDecimal(realTimeMonitorData.getOutputCurrent()));
					info.setVoltageA(new BigDecimal(realTimeMonitorData.getOutputVoltage()));
					info.setSoc(new BigDecimal(realTimeMonitorData.getSOC()));
					info.setStartTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, orderBasicInfo.getChargeStartTime()));
					info.setEndTime(DateUtils.getTime()); // 本次采样时间
					info.setTotalPower(new BigDecimal(realTimeMonitorData.getChargingDegree())); // 累计充电量
					// info.setElecMoney(); // 累计电费
					// info.setSeviceMoney(); // 累计服务费
					info.setTotalMoney(new BigDecimal(realTimeMonitorData.getChargingAmount()));

					ConnectorStatusInfos.add(info);

				} else {
					// 其他
					ConnectorStatusInfo info = new ConnectorStatusInfo();
					info.setConnectorID(connectorInfoVO.getPileConnectorCode());
					info.setStatus(connectorInfoVO.getConnectorStatus());

					ConnectorStatusInfos.add(info);
				}
				StationStatusInfo stationStatusInfo = new StationStatusInfo();
				stationStatusInfo.setStationID(connectorInfoVO.getStationId());
				stationStatusInfo.setConnectorStatusInfos(ConnectorStatusInfos);

				StationStatusInfos.add(stationStatusInfo);
			}
		}
		// 将 StationStatusInfos 分页
		int pageNum = 1;
		int pageSize = 10;
		List<StationStatusInfo> collect = StationStatusInfos.stream()
				.skip((pageNum - 1) * pageSize)
				.limit(pageSize)
				.collect(Collectors.toList());

		int total = StationStatusInfos.size();
		int pages = PageUtil.totalPage(total, pageSize);

		LianLianPageResponse response = LianLianPageResponse.builder()
				.PageCount(pages)
				.PageNo(pageNum)
				.list(collect)
				.ItemSize(total)
				.build();
		return response;
	}

	/**
	 * 查询统计信息
	 * @param dto
	 * @return
	 */
	@Override
	public StationStatsInfo query_station_stats(QueryStationInfoDTO dto) {
		// 根据站点id 查出这段时间的充电量
		List<AccumulativeInfoVO> list = orderBasicInfoService.getAccumulativeInfoForLianLian(dto);
		if (CollectionUtils.isEmpty(list)) {
			return StationStatsInfo.builder()
					.StationID(dto.getStationID())
					.StartTime(dto.getStartTime())
					.EndTime(dto.getEndTime())
					.StationElectricity(BigDecimal.ZERO)
					.equipmentStatsInfos(Lists.newArrayList()) // 设备列表
					.build();
		}

		// 根据充电桩编号分组 key=充电桩编号
		Map<String, List<AccumulativeInfoVO>> pileMap = list.stream()
				.collect(Collectors.groupingBy(AccumulativeInfoVO::getPileSn));

		// 存放所有充电桩设备
		List<EquipmentStatsInfo> equipmentStatsInfoList = Lists.newArrayList();
		// 站点用电量
		BigDecimal stationElectricity = BigDecimal.ZERO;
		// 用于记录枪口用电量 在循环每个枪口的时候初始化
		BigDecimal pileElec;
		for (String pileSn : pileMap.keySet()) {
			// 该充电桩下 所有枪口的用电数据
			List<AccumulativeInfoVO> accumulativeInfoVOS = pileMap.get(pileSn);
			if (CollectionUtils.isEmpty(accumulativeInfoVOS)) {
				continue;
			}

			// 存放充电桩用电量
			pileElec = BigDecimal.ZERO;

			// key=枪口编号  value 该枪口的用电数据
			Map<String, List<AccumulativeInfoVO>> collect = accumulativeInfoVOS.stream()
					.collect(Collectors.groupingBy(AccumulativeInfoVO::getPileConnectorCode));

			List<ConnectorStatsInfo> connectorStatsInfos = Lists.newArrayList();
			for (Map.Entry<String, List<AccumulativeInfoVO>> entry : collect.entrySet()) {
				String pileConnectorCode = entry.getKey();
				List<AccumulativeInfoVO> value = entry.getValue();
				// 枪口用电量求和
				BigDecimal connectorElec = value.stream()
						.map(AccumulativeInfoVO::getConnectorElectricity)
						.map(BigDecimal::new)
						.reduce(BigDecimal.ZERO, BigDecimal::add);

				connectorStatsInfos.add(
						ConnectorStatsInfo.builder()
								.ConnectorID(pileConnectorCode)
								.ConnectorElectricity(connectorElec)
								.build()
				);
				// 充电桩电量为枪口用电量累计
				pileElec = pileElec.add(connectorElec);
			}

			EquipmentStatsInfo build = EquipmentStatsInfo.builder()
					.EquipmentID(pileSn)
					.EquipmentElectricity(pileElec)
					.ConnectorStatsInfos(connectorStatsInfos)
					.build();
			equipmentStatsInfoList.add(build);

			// 所有充电桩用电量之和
			stationElectricity = stationElectricity.add(pileElec);
		}
		
		StationStatsInfo stationStatsInfo = StationStatsInfo.builder()
				.StationID(dto.getStationID())
				.StartTime(dto.getStartTime())
				.EndTime(dto.getEndTime())
				.StationElectricity(stationElectricity)
				.equipmentStatsInfos(equipmentStatsInfoList) // 设备列表
				.build();

		return stationStatsInfo;
	}

	/**
	 * 请求设备认证
	 * @param dto
	 * @return
	 */
	@Override
	public EquipmentAuthVO query_equip_auth(QueryEquipmentDTO dto) {
		EquipmentAuthVO vo = new EquipmentAuthVO();

		String equipAuthSeq = dto.getEquipAuthSeq();
		String pileConnectorCode = dto.getConnectorID();
		// 通过运营商id + 枪口编码查询数据
		String merchantId = StringUtils.substring(equipAuthSeq, 0, 9);
		String pileSn = StringUtils.substring(pileConnectorCode, 0, 14);
		// 能查到为成功
		vo.setSuccStat(1); // 1-失败 0-成功
		PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn);
		if (pileBasicInfo == null) {
			vo.setFailReason(2); // 设备检测失败
			vo.setFailReasonMsg("未查到该桩的数据");
			throw new BusinessException("", "");
		}
		if (pileBasicInfo.getMerchantId() == Long.parseLong(merchantId)) {
			vo.setSuccStat(0);
			// 查询当前数据
			PileConnectorInfoVO connectorInfo = pileConnectorInfoService.getPileConnectorInfoByConnectorCode(pileConnectorCode);
			if (StringUtils.equals(PileConnectorDataBaseStatusEnum.OCCUPIED_NOT_CHARGED.getValue(), String.valueOf(connectorInfo.getStatus()))
				|| StringUtils.equals(PileConnectorDataBaseStatusEnum.OCCUPIED_CHARGING.getValue(), String.valueOf(connectorInfo.getStatus()))
				|| StringUtils.equals(PileConnectorDataBaseStatusEnum.OCCUPIED_APPOINTMENT_LOCK.getValue(), String.valueOf(connectorInfo.getStatus()))
			) {
				vo.setFailReason(0);
			} else {
				vo.setFailReason(1); // 1- 此设备尚未插枪；
			}
			vo.setFailReasonMsg("");
		}

		vo.setEquipAuthSeq(equipAuthSeq);
		vo.setConnectorID(pileConnectorCode);

		return vo;
	}


	/**
	 * 请求启动充电
	 * @param dto
	 */
	public QueryStartChargeVO query_start_charge(QueryStartChargeDTO dto) {
		// 通过传过来的订单号和枪口号生成订单
		// String orderCode = dto.getStartChargeSeq();
		String pileConnectorCode = dto.getConnectorID();
		OrderBasicInfo orderInfo = orderBasicInfoService.getOrderInfoByOrderCode(dto.getStartChargeSeq());
		if (orderInfo != null) {
			// 平台已存在订单
			throw new BusinessException("", "平台已存在订单");
		}

		Map<String, Object> map = orderBasicInfoService.generateOrderForLianLian(dto);
		String orderCode = (String) map.get("orderCode");
		String transactionCode = (String) map.get("transactionCode");
		OrderBasicInfo orderBasicInfo = (OrderBasicInfo) map.get("orderBasicInfo");


		StartChargingCommand command = StartChargingCommand.builder()
				.pileSn(orderBasicInfo.getPileSn())
				.connectorCode(orderBasicInfo.getConnectorCode())
				.transactionCode(transactionCode)
				.chargeAmount(orderBasicInfo.getPayAmount())
				.logicCardNum(null)
				.physicsCardNum(null)
				.build();
		ykcPushCommandService.pushStartChargingCommand(command);

		// 拼装对应的数据并返回
		QueryStartChargeVO vo = QueryStartChargeVO.builder()
				.StartChargeSeq(orderCode)
				.StartChargeSeqStat(1) // 1-启动中
				.ConnectorID(pileConnectorCode)
				.SuccStat(0)
				.FailReason(0)

				.build();
		return vo;

		// TODO 推送启动充电结果(调用接口 notification_start_charge_result)
	}


	/**
	 * 查询充电状态
	 * @param startChargeSeq
	 * @return
	 */
	public QueryChargingStatusVO query_equip_charge_status(String startChargeSeq) {
		// 通过订单号查询订单信息
		OrderBasicInfo orderInfo = orderBasicInfoService.getOrderInfoByOrderCode(startChargeSeq);
		// 通过订单号查询实时数据
		if (orderInfo == null) {
			throw new BusinessException("", "");
		}
		// OrderDetail orderDetail = orderBasicInfoService.getOrderDetailByOrderCode(orderInfo.getOrderCode());
		List<RealTimeMonitorData> realTimeData = orderBasicInfoService.getChargingRealTimeData(orderInfo.getTransactionCode());
		RealTimeMonitorData data = realTimeData.get(0);
		String orderStatus = orderInfo.getOrderStatus();
		if (StringUtils.equals(orderStatus, OrderStatusEnum.IN_THE_CHARGING.getValue())) {
			// 充电中
			orderStatus = "2";
		}if (StringUtils.equals(orderStatus, OrderStatusEnum.ORDER_COMPLETE.getValue())) {
			// 充电完成
			orderStatus = "4";
		}else {
			// 直接给 5-未知
			orderStatus = "5";
		}
		// 拼装联联平台数据
		QueryChargingStatusVO vo = QueryChargingStatusVO.builder()
				.StartChargeSeq(startChargeSeq) // 订单号
				.StartChargeSeqStat(Integer.parseInt(orderStatus)) // 订单状态
				.ConnectorID(orderInfo.getPileConnectorCode()) // 枪口编码
				.ConnectorStatus(Integer.parseInt(data.getConnectorStatus())) // 枪口状态
				.CurrentA(new BigDecimal(data.getOutputCurrent())) // 电流
				.VoltageA(new BigDecimal(data.getOutputVoltage())) // 电压
				.Soc(new BigDecimal(data.getSOC()))
				.StartTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, orderInfo.getChargeStartTime())) // 开始时间
				.EndTime(DateUtils.getTime()) // 本次采样时间
				.TotalPower(new BigDecimal(data.getChargingDegree())) // 累计充电量
				// .ElecMoney(new BigDecimal()) // 累计电费
				// .SeviceMoney(new BigDecimal()) // 累计服务费
				.TotalMoney(new BigDecimal(data.getChargingAmount())) // 已充金额

				.build();


		return vo;
	}


	/**
	 * 请求停止充电
	 * @param dto
	 * @return
	 */
	public QueryStopChargeVO query_stop_charge(QueryStartChargeDTO dto) {
		QueryStopChargeVO vo = new QueryStopChargeVO();

		String orderCode = dto.getStartChargeSeq();

		// 根据订单号查询订单信息
		OrderBasicInfo orderInfo = orderBasicInfoService.getOrderInfoByOrderCode(orderCode);
		if (orderInfo == null) {
			throw new BusinessException("", "");
		}
		// 若状态为充电中，则发送停机指令
		if (StringUtils.equals(OrderStatusEnum.IN_THE_CHARGING.getValue(), orderInfo.getOrderStatus())) {
			// 充电中
			StopChargingCommand command = StopChargingCommand.builder()
					.pileSn(orderInfo.getPileSn())
					.connectorCode(orderInfo.getConnectorCode())
					.build();
			ykcPushCommandService.pushStopChargingCommand(command);
			vo.setStartChargeSeq(orderCode);
			vo.setStartChargeSeqStat(3); // 3-停止中
		}
		return vo;
	}

	/**
	 * 从联联平台获取令牌
	 * @param dto
	 * @return
	 */
	@Override
	public String getToken(String operatorId, String operatorSecret) {
		// String operatorId = dto.getOperatorId();
		// String operatorSecret = dto.getOperatorSecret();
		String token = "";
		try {
			//测试用请求地址
			String requestUrl = TEST_URL + "query_token";

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

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

			Map<String, String> request = new LinkedHashMap<>();
			request.put("OperatorID", operatorId);
			request.put("Data", strData);
			request.put("TimeStamp", System.currentTimeMillis() + "");
			request.put("Seq", "0001");

			//生成签名
			String sig = GBSignUtils.sign(request, operatorSecret);
			request.put("Sig", sig);

			String tokenRequest = JSONUtil.toJsonStr(request);

			String response = HttpUtil.post(requestUrl, tokenRequest);
			LianLianResultVO result = JSON.parseObject(response, LianLianResultVO.class);

			if (result.getRet() == 0) {
				//解密data
				byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64((String) result.getData()),
						operatorSecret.getBytes(), operatorSecret.getBytes());
				String dataStr = new String(plainText, "UTF-8");
				Map<String, String> resultMap = (Map<String, String>) JSON.parse(dataStr);
				token = resultMap.get("AccessToken");
			}
		} catch (Exception e) {
			return token;
		}
		return token;
	}

	/**
	 * 联联平台推送 设备状态变化推送
	 * @param pileConnectorCode
	 * @param status
	 * @return
	 */
	@Override
	public String pushConnectorStatus(String pileConnectorCode, String status) {
		String url = TEST_URL + "notification_stationStatus";

		// 获取令牌
		String token = getToken(OPERATOR_ID, OPERATOR_SECRET);
		if (StringUtils.isBlank(token)) {
			return null;
		}
		ConnectorStatusInfo info = ConnectorStatusInfo.builder()
				.connectorID(pileConnectorCode)
				.status(status)
				.build();
		// 调用联联平台接口
		JSONObject json = new JSONObject();
		json.put("ConnectorStatusInfo", info);
		String jsonString = JSONObject.toJSONString(json);

		String result = HttpRequestUtil.sendPost(token, jsonString, url, DATA_SECRET, DATA_SECRETIV, OPERATOR_ID, SIG_SECRET);

		return result;
	}

	@Override
	public String pushOrderInfo(String orderCode) {
		List<ChargeDetail> chargeDetails = new ArrayList<>();
		// 根据订单号查询出信息
		OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(orderCode);
		OrderDetail orderDetail = orderBasicInfoService.getOrderDetailByOrderCode(orderCode);

		String url = TEST_URL + "notification_orderInfo";

		// 拼装成联联平台所需格式对象
		OrderInfo orderInfo = OrderInfo.builder()
				.operatorID(OPERATOR_ID)
				.equipmentOwnerID(Constants.OPERATORID_LIANLIAN)
				.stationID(orderBasicInfo.getStationId())
				.equipmentID(orderBasicInfo.getPileSn())
				.connectorID(orderBasicInfo.getPileConnectorCode())
				.startChargeSeq(orderCode)
				.userChargeType(Constants.one)
				.money(new BigDecimal(String.valueOf(orderBasicInfo.getOrderAmount())).setScale(2, BigDecimal.ROUND_HALF_UP))
				.electMoney(new BigDecimal(String.valueOf(orderDetail.getTotalElectricityAmount())).setScale(2, BigDecimal.ROUND_HALF_UP))
				.serviceMoney(new BigDecimal(String.valueOf(orderDetail.getTotalServiceAmount())).setScale(2, BigDecimal.ROUND_HALF_UP))
				.elect(new BigDecimal(String.valueOf(orderDetail.getTotalUsedElectricity())).setScale(2, BigDecimal.ROUND_HALF_UP))
				.startTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, orderBasicInfo.getChargeStartTime()))
				.endTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, orderBasicInfo.getChargeEndTime()))
				.paymentAmount(orderBasicInfo.getPayAmount())
				// .payChannel()
				.stopReason(0)
				// .chargeDetails()
				.build();
		// 支付方式
		if (StringUtils.equals(orderBasicInfo.getPayMode(), OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue())) {
			// 微信支付
			orderInfo.setPayChannel(Integer.valueOf(PayChannelEnum.WEXIN_PAY.getCode()));
		}else if (StringUtils.equals(orderBasicInfo.getPayMode(), OrderPayModeEnum.PAYMENT_OF_ALIPAY.getValue())) {
			// 支付宝支付
			orderInfo.setPayChannel(Integer.valueOf(PayChannelEnum.ALI_PAY.getCode()));
		}else {
			// 其他
			orderInfo.setPayChannel(Integer.valueOf(PayChannelEnum.OTHER.getCode()));
		}
		// 订单详情
		ChargeDetail detail;

		List<BillingPriceVO> billingList = pileBillingTemplateService.queryBillingPrice(orderBasicInfo.getStationId());
		// 先将list按照 尖、峰、平、谷 时段排序
		// List<BillingPriceVO> collect = billingList.stream().sorted(Comparator.comparing(BillingPriceVO::getTimeType)).collect(Collectors.toList());
		// 再循环该list，拼装对应的充电价格、费率
		for (BillingPriceVO billingPriceVO : billingList) {
			detail = new ChargeDetail();
			if (StringUtils.equals(billingPriceVO.getTimeType(), "1")) {
				// 尖时段
				detail.setDetailStartTime(billingPriceVO.getStartTime());
				detail.setDetailEndTime(billingPriceVO.getEndTime());
				detail.setElecPrice(new BigDecimal(billingPriceVO.getElectricityPrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setSevicePrice(new BigDecimal(billingPriceVO.getServicePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setDetailPower(orderDetail.getSharpUsedElectricity());
				detail.setDetailElecMoney(orderDetail.getSharpElectricityPrice());
				detail.setDetailSeviceMoney(orderDetail.getSharpServicePrice());
			}else if (StringUtils.equals(billingPriceVO.getTimeType(), "2")) {
				// 峰时段
				detail.setDetailStartTime(billingPriceVO.getStartTime());
				detail.setDetailEndTime(billingPriceVO.getEndTime());
				detail.setElecPrice(new BigDecimal(billingPriceVO.getElectricityPrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setSevicePrice(new BigDecimal(billingPriceVO.getServicePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setDetailPower(orderDetail.getPeakUsedElectricity());
				detail.setDetailElecMoney(orderDetail.getPeakElectricityPrice());
				detail.setDetailSeviceMoney(orderDetail.getPeakServicePrice());
			}else if (StringUtils.equals(billingPriceVO.getTimeType(), "3")) {
				// 平时段
				detail.setDetailStartTime(billingPriceVO.getStartTime());
				detail.setDetailEndTime(billingPriceVO.getEndTime());
				detail.setElecPrice(new BigDecimal(billingPriceVO.getElectricityPrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setSevicePrice(new BigDecimal(billingPriceVO.getServicePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setDetailPower(orderDetail.getFlatUsedElectricity());
				detail.setDetailElecMoney(orderDetail.getFlatElectricityPrice());
				detail.setDetailSeviceMoney(orderDetail.getFlatServicePrice());
			}else if (StringUtils.equals(billingPriceVO.getTimeType(), "4")) {
				// 谷时段
				detail.setDetailStartTime(billingPriceVO.getStartTime());
				detail.setDetailEndTime(billingPriceVO.getEndTime());
				detail.setElecPrice(new BigDecimal(billingPriceVO.getElectricityPrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setSevicePrice(new BigDecimal(billingPriceVO.getServicePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));
				detail.setDetailPower(orderDetail.getValleyUsedElectricity());
				detail.setDetailElecMoney(orderDetail.getValleyElectricityPrice());
				detail.setDetailSeviceMoney(orderDetail.getValleyServicePrice());
			}
			chargeDetails.add(detail);
		}

		orderInfo.setChargeDetails(chargeDetails);

		// 获取令牌
		String token = getToken(OPERATOR_ID, OPERATOR_SECRET);
		if (StringUtils.isBlank(token)) {
			return null;
		}
		// 调用联联平台接口
		JSONObject json = new JSONObject();
		json.put("OrderInfo", orderInfo);
		String jsonString = JSONObject.toJSONString(json);

		String result = HttpRequestUtil.sendPost(token, jsonString, url, DATA_SECRET, DATA_SECRETIV, OPERATOR_ID, SIG_SECRET);

		return result;
	}

	// private ChargeDetail setChargeDetail(OrderBasicInfo orderBasicInfo, OrderDetail orderDetail) {
	// 	ChargeDetail detail = new ChargeDetail();
	//
	// 	detail.setDetailStartTime();
	// 	detail.setDetailEndTime();
	// 	detail.setElecPrice();
	// 	detail.setSevicePrice();
	// 	detail.setDetailPower();
	// 	detail.setDetailElecMoney();
	// 	detail.setDetailSeviceMoney();
	// }

	// TODO 推送停止充电结果  notification_stop_charge_result

	// TODO 推送充电订单信息  notification_charge_order_info

	// TODO 推送订单对账结果信息  check_charge_orders

	/**
	 * TODO 请求打印充电小票
	 */
	public void query_print_parking_ticket() {

	}


	// TODO 推送订单结算信息  notification_order_settlement_info

	// TODO 查询订单结算信息  query_order_settlement_info



	/**
	 * 获取桩列表信息
	 * @param pileStationInfo
	 * @return
	 */
	private List<EquipmentInfo> getPileList(PileStationInfo pileStationInfo){
		List<EquipmentInfo> resultList = new ArrayList<>();
		// 通过站点id查询桩基本信息
		List<PileBasicInfo> list = pileBasicInfoService.getPileListByStationId(String.valueOf(pileStationInfo.getId()));
		MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(String.valueOf(pileStationInfo.getMerchantId()));
		// 封装成联联平台对象
		for (PileBasicInfo pileBasicInfo : list) {
			EquipmentInfo equipmentInfo = new EquipmentInfo();
			String pileSn = pileBasicInfo.getSn();

			equipmentInfo.setEquipmentID(pileSn);
			equipmentInfo.setManufacturerID(Constants.OPERATORID_LIANLIAN);
			equipmentInfo.setConstructionTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, pileBasicInfo.getCreateTime()));

			PileModelInfoVO modelInfo = pileModelInfoService.getPileModelInfoByPileSn(pileSn);
			equipmentInfo.setEquipmentType(Integer.valueOf(modelInfo.getSpeedType()));

			// Map<String, String> pileStatus = pileConnectorInfoService.getPileStatus(Lists.newArrayList(pileBasicInfo.getSn()));
			Map<String, String> pileStatusMap = pileConnectorInfoService.getPileStatus(Lists.newArrayList(pileSn));
			String pileStatus = pileStatusMap.get(pileSn);
			if (StringUtils.equals(PileStatusEnum.ON_LINE.getValue(), pileStatus)) {
				// 1-在线
				pileStatus = LianLianPileStatusEnum.NORMAL.getCode();
			} else if (StringUtils.equals(PileStatusEnum.OFF_LINE.getValue(), pileStatus)) {
				// 2-离线
				pileStatus = LianLianPileStatusEnum.CLOSE_OFFLINE.getCode();
			} else if (StringUtils.equals(PileStatusEnum.FAULT.getValue(), pileStatus)) {
				// 3-故障
				pileStatus = LianLianPileStatusEnum.UNDER_MAINTENANCE.getCode();
			}
			equipmentInfo.setEquipmentStatus(Integer.valueOf(pileStatus));
			equipmentInfo.setEquipmentPower(new BigDecimal(modelInfo.getRatedPower()).setScale(1, BigDecimal.ROUND_HALF_UP));
			equipmentInfo.setNewNationalStandard(1);
			equipmentInfo.setVinFlag(1);

			List<ConnectorInfo> connectorList = getConnectorList(pileBasicInfo);
			equipmentInfo.setConnectorInfos(connectorList);

			resultList.add(equipmentInfo);
		}
		return resultList;
	}


	/**
	 * 获取枪口列表
	 * @param pileBasicInfo
	 * @return
	 */
	private List<ConnectorInfo> getConnectorList(PileBasicInfo pileBasicInfo){
		List<ConnectorInfo> resultList = new ArrayList<>();

		List<PileConnectorInfo> list = pileConnectorInfoService.selectPileConnectorInfoList(pileBasicInfo.getSn());
		for (PileConnectorInfo pileConnectorInfo : list) {
			ConnectorInfo connectorInfo = new ConnectorInfo();

			connectorInfo.setConnectorID(pileConnectorInfo.getPileConnectorCode());
			String pileSn = pileConnectorInfo.getPileSn();
			PileModelInfoVO modelInfo = pileModelInfoService.getPileModelInfoByPileSn(pileSn);
			int connectorType = StringUtils.equals("1", modelInfo.getSpeedType()) ? 4 : 3;

			connectorInfo.setConnectorType(connectorType);
			connectorInfo.setVoltageUpperLimits(Integer.valueOf(modelInfo.getRatedVoltage()));
			connectorInfo.setVoltageLowerLimits(Integer.valueOf(modelInfo.getRatedVoltage()));
			connectorInfo.setCurrent(Integer.valueOf(modelInfo.getRatedCurrent()));
			connectorInfo.setPower(new BigDecimal(modelInfo.getRatedPower()).setScale(1, BigDecimal.ROUND_HALF_UP));

			resultList.add(connectorInfo);
		}

		return resultList;
	}
}
