package com.jsowell.netty.handler;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.primitives.Bytes;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ykc.TransactionRecordsData;
import com.jsowell.common.core.domain.ykc.YKCDataProtocol;
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.ykc.CardStatusEnum;
import com.jsowell.common.enums.ykc.OrderStatusEnum;
import com.jsowell.common.enums.ykc.YKCChargingStopReasonEnum;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.Cp56Time2a.Cp56Time2aUtil;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.common.util.id.IdUtils;
import com.jsowell.netty.factory.YKCOperateFactory;
import com.jsowell.pile.domain.*;
import com.jsowell.pile.service.*;
import com.jsowell.pile.vo.base.StationSettingRelationVO;
import com.jsowell.thirdparty.lianlian.service.LianLianService;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Objects;

/**
 * 交易记录确认
 * 这一帧仅是报文交互使用， 意指平台成功接收到交易记录报文，并不代表交易订单成功结算
 * 运营平台接收到结算账单上传后，都需回复此确认信息。若桩未收到回复帧，则 5 分钟后继续 上送一次交易记录，
 * 此情况下无论平台是否成功回复都停止上送。
 *
 * @author JS-ZZA
 * @date 2022/9/19 14:40
 */
@Slf4j
@Component
public class TransactionRecordsRequestHandler extends AbstractHandler {
	private final String type = YKCUtils.frameType2Str(YKCFrameTypeCode.TRANSACTION_RECORDS_CODE.getBytes());
	private final String oldVersionType = YKCUtils.frameType2Str(YKCFrameTypeCode.TRANSACTION_RECORDS_OLD_VERSION_CODE.getBytes());

	@Override
	public void afterPropertiesSet() throws Exception {
		YKCOperateFactory.register(type, this);
		YKCOperateFactory.register(oldVersionType, this);
	}

	@Autowired
	private RedisCache redisCache;

	@Autowired
	private IPileMsgRecordService pileMsgRecordService;

	@Autowired
	private IOrderBasicInfoService orderBasicInfoService;

	@Autowired
	private IPileAuthCardService pileAuthCardService;

	@Autowired
	private IThirdPartySettingInfoService thirdPartySettingInfoService;

	@Autowired
	private LianLianService lianLianService;

	@Autowired
	private IStationSettingRelationService stationSettingRelationService;

	@Autowired
	private IMemberPlateNumberRelationService memberPlateNumberRelationService;

	public static void main(String[] args) {
		// 获取消息体
		String msg = "000000000000000000000000000000008823000000030601a08c2e0d0404170000380d0404170000000000000000000000000000000000000000000000000000000000000000400d0300ee250000ee250000c84b000000000000000000000000000000000000e0bb040000cee1040000ee250000ee250000c84b00000000000000000000000000000000000000010000380d04041745a511101970000000";
		byte[] msgBody = BytesUtil.str2Bcd(msg);

		int startIndex = 0;
		int length = 16;

		// 交易流水号
		byte[] orderCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String transactionCode = BytesUtil.bcd2Str(orderCodeByteArr);

		// 桩编码
		startIndex += length;
		length = 7;
		byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String pileSn = BytesUtil.bcd2Str(pileSnByteArr);

		// 枪号
		startIndex += length;
		length = 1;
		byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String connectorCode = BytesUtil.bcd2Str(connectorCodeByteArr);


		// 开始时间  CP56Time2a 格式
		startIndex += length;
		length = 7;
		byte[] startTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		// String binary = BytesUtil.binary(startTimeByteArr, 16);
		Date startDate = Cp56Time2aUtil.byte2Hdate(startTimeByteArr);
		String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startDate);


		// 结束时间  CP56Time2a 格式
		startIndex += length;
		byte[] endTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		Date endDate = Cp56Time2aUtil.byte2Hdate(endTimeByteArr);
		String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endDate);

		// 尖单价   精确到小数点后五位（尖电费+尖服务费，见费率帧）
		startIndex += length;
		length = 4;
		byte[] sharpPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpPrice = YKCUtils.convertDecimalPoint(sharpPriceByteArr, 5);

		// 尖电量   精确到小数点后四位
		startIndex += length;
		length = 4;
		byte[] sharpUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpUsedElectricity = YKCUtils.convertDecimalPoint(sharpUsedElectricityByteArr, 4);

		// 计损尖电量
		startIndex += length;
		byte[] sharpPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpPlanLossElectricity = YKCUtils.convertDecimalPoint(sharpPlanLossElectricityByteArr, 4);

		// 尖金额
		startIndex += length;
		byte[] sharpAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpAmount = YKCUtils.convertDecimalPoint(sharpAmountByteArr, 4);

		// 峰单价   精确到小数点后五位（峰电费+峰服务费）
		startIndex += length;
		byte[] peakPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakPrice = YKCUtils.convertDecimalPoint(peakPriceByteArr, 5);

		// 峰电量
		startIndex += length;
		byte[] peakUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakUsedElectricity = YKCUtils.convertDecimalPoint(peakUsedElectricityByteArr, 4);

		// 计损峰电量
		startIndex += length;
		byte[] peakPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakPlanLossElectricity = YKCUtils.convertDecimalPoint(peakPlanLossElectricityByteArr, 4);

		// 峰金额
		startIndex += length;
		byte[] peakAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakAmount = YKCUtils.convertDecimalPoint(peakAmountByteArr, 4);

		// 平单价   精确到小数点后五位（平电费+平服务费）
		startIndex += length;
		byte[] flatPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatPrice = YKCUtils.convertDecimalPoint(flatPriceByteArr, 5);

		// 平电量
		startIndex += length;
		byte[] flatUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatUsedElectricity = YKCUtils.convertDecimalPoint(flatUsedElectricityByteArr, 4);

		// 计损平电量
		startIndex += length;
		byte[] flatPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatPlanLossElectricity = YKCUtils.convertDecimalPoint(flatPlanLossElectricityByteArr, 4);

		// 平金额
		startIndex += length;
		byte[] flatAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatAmount = YKCUtils.convertDecimalPoint(flatAmountByteArr, 4);

		// 谷单价   精确到小数点后五位（谷电费+谷 服务费）
		startIndex += length;
		byte[] valleyPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyPrice = YKCUtils.convertDecimalPoint(valleyPriceByteArr, 5);

		// 谷电量
		startIndex += length;
		byte[] valleyUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyUsedElectricity = YKCUtils.convertDecimalPoint(valleyUsedElectricityByteArr, 4);

		// 计损谷电量
		startIndex += length;
		byte[] valleyPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyPlanLossElectricity = YKCUtils.convertDecimalPoint(valleyPlanLossElectricityByteArr, 4);

		// 谷金额
		startIndex += length;
		byte[] valleyAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyAmount = YKCUtils.convertDecimalPoint(valleyAmountByteArr, 4);

		// 电表总起值
		startIndex += length;
		length = 5;
		byte[] ammeterTotalStartByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String ammeterTotalStart = YKCUtils.convertDecimalPoint(ammeterTotalStartByteArr, 4);

		// 电表总止值
		startIndex += length;
		byte[] ammeterTotalEndByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String ammeterTotalEnd = YKCUtils.convertDecimalPoint(ammeterTotalEndByteArr, 4);

		// 总电量
		startIndex += length;
		length = 4;
		byte[] totalElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String totalElectricity = YKCUtils.convertDecimalPoint(totalElectricityByteArr, 4);

		// 计损总电量
		startIndex += length;
		byte[] planLossTotalElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String planLossTotalElectricity = YKCUtils.convertDecimalPoint(planLossTotalElectricityByteArr, 4);

		// 消费金额   精确到小数点后四位，包含电费、 服务费
		startIndex += length;
		byte[] consumptionAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String consumptionAmount = YKCUtils.convertDecimalPoint(consumptionAmountByteArr, 4);

		// VIN 码   VIN 码，此处 VIN 码和充电时 VIN 码不同， 正序直接上传， 无需补 0 和反序
		startIndex += length;
		length = 17;
		byte[] vinCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String vinCode = BytesUtil.ascii2Str(vinCodeByteArr);

		/**
		 * 交易标识
		 * 0x01： app 启动
		 * 0x02：卡启动
		 * 0x04：离线卡启动
		 * 0x05: vin 码启动充电
		 */
	startIndex += length;
	length = 1;
	byte[] transactionIdentifierByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
	String transactionIdentifier = BytesUtil.bcd2Str(transactionIdentifierByteArr);

	// 交易时间  CP56Time2a 格式
	startIndex += length;
	length = 7;
	byte[] transactionTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
	Date transactionDate = Cp56Time2aUtil.byte2Hdate(transactionTimeByteArr);
	String transactionTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, transactionDate);

	// 停止原因
	startIndex += length;
	length = 1;
	byte[] stopReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
	String stopReason = BytesUtil.bin2HexStr(stopReasonByteArr);
	String stopReasonMsg = YKCChargingStopReasonEnum.getMsgByCode(Integer.parseInt(stopReason, 16));

	// 物理卡号  不足 8 位补 0
	startIndex += length;
	length = 8;
	byte[] cardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
	// byte[] logicCardNum = BytesUtil.checkLengthAndBehindAppendZero(cardNumByteArr, 16);
	String logicCard = BytesUtil.binary(cardNumByteArr, 16);
		log.info("桩号:{}发送交易记录物理卡号:{}", pileSn, logicCard);

		log.info("[===交易记录===]交易流水号:{}, 桩编号:{}, 枪号:{}, 开始时间:{}, 结束时间:{}, 尖单价:{}, 尖电量:{}, 计损尖电量:{}, 尖金额:{}, " +
				"峰单价:{}, 峰电量:{}, 计损峰电量:{}, 峰金额:{}, 平单价:{}, 平电量:{}, 计损平电量:{}, 平金额:{}, " +
				"谷单价:{}, 谷电量:{}, 计损谷电量:{}, 谷金额:{}, 电表总起值:{}, 电表总止值:{}, 总电量:{}, 计损总电量:{}, 消费金额:{}, " +
				"电动汽车唯一标识:{}, 交易标识:{}, 交易日期、时间:{}, 停止原因码:{}, 停止原因描述:{}, 物理卡号:{}",
	transactionCode, pileSn, connectorCode, startTime, endTime, sharpPrice, sharpUsedElectricity, sharpPlanLossElectricity, sharpAmount,
	peakPrice, peakUsedElectricity, peakPlanLossElectricity, peakAmount, flatPrice, flatUsedElectricity, flatPlanLossElectricity, flatAmount,
	valleyPrice, valleyUsedElectricity, valleyPlanLossElectricity, valleyAmount, ammeterTotalStart, ammeterTotalEnd, totalElectricity, planLossTotalElectricity,
	consumptionAmount, vinCode, transactionIdentifier, transactionTime, stopReason, stopReasonMsg, logicCard);

		// 交易记录封装到对象里
		TransactionRecordsData data = TransactionRecordsData.builder()
				// .orderCode(transactionCode)
				.transactionCode(transactionCode)
				.pileSn(pileSn)
				.connectorCode(connectorCode)
				.startTime(startTime)
				.endTime(endTime)
				.sharpPrice(sharpPrice)
				.sharpUsedElectricity(sharpUsedElectricity)
				.sharpPlanLossElectricity(sharpPlanLossElectricity)
				.sharpAmount(sharpAmount)
				.peakPrice(peakPrice)
				.peakUsedElectricity(peakUsedElectricity)
				.peakPlanLossElectricity(peakPlanLossElectricity)
				.peakAmount(peakAmount)
				.flatPrice(flatPrice)
				.flatUsedElectricity(flatUsedElectricity)
				.flatPlanLossElectricity(flatPlanLossElectricity)
				.flatAmount(flatAmount)
				.valleyPrice(valleyPrice)
				.valleyUsedElectricity(valleyUsedElectricity)
				.valleyPlanLossElectricity(valleyPlanLossElectricity)
				.valleyAmount(valleyAmount)
				.ammeterTotalStart(ammeterTotalStart)
				.ammeterTotalEnd(ammeterTotalEnd)
				.totalElectricity(totalElectricity)
				.planLossTotalElectricity(planLossTotalElectricity)
				.consumptionAmount(consumptionAmount)
				.vinCode(vinCode)
				.transactionIdentifier(transactionIdentifier)
				.transactionTime(transactionTime)
				.stopReasonMsg(stopReasonMsg)
				.logicCard(logicCard)
				.build();

		boolean flag = !StringUtils.equals("0000000000000000", "a511101970000000");
		System.out.println(flag);

	}

	@Override
	public byte[] supplyProcess(YKCDataProtocol ykcDataProtocol, Channel channel) {
		// log.info("[===交易记录===] param:{}, channel:{}", JSONObject.toJSONString(ykcDataProtocol), channel.toString());
		// 获取消息体
		byte[] msgBody = ykcDataProtocol.getMsgBody();

		int startIndex = 0;
		int length = 16;

		// 交易流水号
		byte[] orderCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String transactionCode = BytesUtil.bcd2Str(orderCodeByteArr);

		// 桩编码
		startIndex += length;
		length = 7;
		byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String pileSn = BytesUtil.bcd2Str(pileSnByteArr);

		// 枪号
		startIndex += length;
		length = 1;
		byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String connectorCode = BytesUtil.bcd2Str(connectorCodeByteArr);


		// 开始时间  CP56Time2a 格式
		startIndex += length;
		length = 7;
		byte[] startTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		// String binary = BytesUtil.binary(startTimeByteArr, 16);
		Date startDate = Cp56Time2aUtil.byte2Hdate(startTimeByteArr);
		String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startDate);


		// 结束时间  CP56Time2a 格式
		startIndex += length;
		byte[] endTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		Date endDate = Cp56Time2aUtil.byte2Hdate(endTimeByteArr);
		String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endDate);

		// 尖单价   精确到小数点后五位（尖电费+尖服务费，见费率帧）
		startIndex += length;
		length = 4;
		byte[] sharpPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpPrice = YKCUtils.convertDecimalPoint(sharpPriceByteArr, 5);

		// 尖电量   精确到小数点后四位
		startIndex += length;
		length = 4;
		byte[] sharpUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpUsedElectricity = YKCUtils.convertDecimalPoint(sharpUsedElectricityByteArr, 4);

		// 计损尖电量
		startIndex += length;
		byte[] sharpPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpPlanLossElectricity = YKCUtils.convertDecimalPoint(sharpPlanLossElectricityByteArr, 4);

		// 尖金额
		startIndex += length;
		byte[] sharpAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String sharpAmount = YKCUtils.convertDecimalPoint(sharpAmountByteArr, 4);

		// 峰单价   精确到小数点后五位（峰电费+峰服务费）
		startIndex += length;
		byte[] peakPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakPrice = YKCUtils.convertDecimalPoint(peakPriceByteArr, 5);

		// 峰电量
		startIndex += length;
		byte[] peakUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakUsedElectricity = YKCUtils.convertDecimalPoint(peakUsedElectricityByteArr, 4);

		// 计损峰电量
		startIndex += length;
		byte[] peakPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakPlanLossElectricity = YKCUtils.convertDecimalPoint(peakPlanLossElectricityByteArr, 4);

		// 峰金额
		startIndex += length;
		byte[] peakAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String peakAmount = YKCUtils.convertDecimalPoint(peakAmountByteArr, 4);

		// 平单价   精确到小数点后五位（平电费+平服务费）
		startIndex += length;
		byte[] flatPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatPrice = YKCUtils.convertDecimalPoint(flatPriceByteArr, 5);

		// 平电量
		startIndex += length;
		byte[] flatUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatUsedElectricity = YKCUtils.convertDecimalPoint(flatUsedElectricityByteArr, 4);

		// 计损平电量
		startIndex += length;
		byte[] flatPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatPlanLossElectricity = YKCUtils.convertDecimalPoint(flatPlanLossElectricityByteArr, 4);

		// 平金额
		startIndex += length;
		byte[] flatAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String flatAmount = YKCUtils.convertDecimalPoint(flatAmountByteArr, 4);

		// 谷单价   精确到小数点后五位（谷电费+谷 服务费）
		startIndex += length;
		byte[] valleyPriceByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyPrice = YKCUtils.convertDecimalPoint(valleyPriceByteArr, 5);

		// 谷电量
		startIndex += length;
		byte[] valleyUsedElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyUsedElectricity = YKCUtils.convertDecimalPoint(valleyUsedElectricityByteArr, 4);

		// 计损谷电量
		startIndex += length;
		byte[] valleyPlanLossElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyPlanLossElectricity = YKCUtils.convertDecimalPoint(valleyPlanLossElectricityByteArr, 4);

		// 谷金额
		startIndex += length;
		byte[] valleyAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String valleyAmount = YKCUtils.convertDecimalPoint(valleyAmountByteArr, 4);

		// 电表总起值
		startIndex += length;
		length = 5;
		byte[] ammeterTotalStartByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String ammeterTotalStart = YKCUtils.convertDecimalPoint(ammeterTotalStartByteArr, 4);

		// 电表总止值
		startIndex += length;
		byte[] ammeterTotalEndByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String ammeterTotalEnd = YKCUtils.convertDecimalPoint(ammeterTotalEndByteArr, 4);

		// 总电量
		startIndex += length;
		length = 4;
		byte[] totalElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String totalElectricity = YKCUtils.convertDecimalPoint(totalElectricityByteArr, 4);

		// 计损总电量
		startIndex += length;
		byte[] planLossTotalElectricityByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String planLossTotalElectricity = YKCUtils.convertDecimalPoint(planLossTotalElectricityByteArr, 4);

		// 消费金额   精确到小数点后四位，包含电费、 服务费
		startIndex += length;
		byte[] consumptionAmountByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String consumptionAmount = YKCUtils.convertDecimalPoint(consumptionAmountByteArr, 4);

		// VIN 码   VIN 码，此处 VIN 码和充电时 VIN 码不同， 正序直接上传， 无需补 0 和反序
		startIndex += length;
		length = 17;
		byte[] vinCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String vinCode = BytesUtil.ascii2Str(vinCodeByteArr);

		/**
		 * 交易标识
		 * 0x01： app 启动
		 * 0x02：卡启动
		 * 0x04：离线卡启动
		 * 0x05: vin 码启动充电
		 */
		startIndex += length;
		length = 1;
		byte[] transactionIdentifierByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String transactionIdentifier = BytesUtil.bcd2Str(transactionIdentifierByteArr);

		// 交易时间  CP56Time2a 格式
		startIndex += length;
		length = 7;
		byte[] transactionTimeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		Date transactionDate = Cp56Time2aUtil.byte2Hdate(transactionTimeByteArr);
		String transactionTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, transactionDate);

		// 停止原因
		startIndex += length;
		length = 1;
		byte[] stopReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String stopReason = BytesUtil.bin2HexStr(stopReasonByteArr);
		String stopReasonMsg = YKCChargingStopReasonEnum.getMsgByCode(Integer.parseInt(stopReason, 16));

		// 物理卡号  不足 8 位补 0
		startIndex += length;
		length = 8;
		byte[] cardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		// byte[] logicCardNum = BytesUtil.checkLengthAndBehindAppendZero(cardNumByteArr, 16);
		String logicCard = BytesUtil.binary(cardNumByteArr, 16);
		log.info("桩号:{}发送交易记录物理卡号:{}", pileSn, logicCard);

		log.info("[===交易记录===]交易流水号:{}, 桩编号:{}, 枪号:{}, 开始时间:{}, 结束时间:{}, 尖单价:{}, 尖电量:{}, 计损尖电量:{}, 尖金额:{}, " +
				"峰单价:{}, 峰电量:{}, 计损峰电量:{}, 峰金额:{}, 平单价:{}, 平电量:{}, 计损平电量:{}, 平金额:{}, " +
				"谷单价:{}, 谷电量:{}, 计损谷电量:{}, 谷金额:{}, 电表总起值:{}, 电表总止值:{}, 总电量:{}, 计损总电量:{}, 消费金额:{}, " +
				"vin码:{}, 交易标识:{}, 交易日期、时间:{}, 停止原因码:{}, 停止原因描述:{}, 物理卡号:{}",
				transactionCode, pileSn, connectorCode, startTime, endTime, sharpPrice, sharpUsedElectricity, sharpPlanLossElectricity, sharpAmount,
				peakPrice, peakUsedElectricity, peakPlanLossElectricity, peakAmount, flatPrice, flatUsedElectricity, flatPlanLossElectricity, flatAmount,
				valleyPrice, valleyUsedElectricity, valleyPlanLossElectricity, valleyAmount, ammeterTotalStart, ammeterTotalEnd, totalElectricity, planLossTotalElectricity,
				consumptionAmount, vinCode, transactionIdentifier, transactionTime, stopReason, stopReasonMsg, logicCard);

		// 交易记录封装到对象里
		TransactionRecordsData data = TransactionRecordsData.builder()
				// .orderCode(transactionCode)
				.transactionCode(transactionCode)
				.pileSn(pileSn)
				.connectorCode(connectorCode)
				.startTime(startTime)
				.endTime(endTime)
				.sharpPrice(sharpPrice)
				.sharpUsedElectricity(sharpUsedElectricity)
				.sharpPlanLossElectricity(sharpPlanLossElectricity)
				.sharpAmount(sharpAmount)
				.peakPrice(peakPrice)
				.peakUsedElectricity(peakUsedElectricity)
				.peakPlanLossElectricity(peakPlanLossElectricity)
				.peakAmount(peakAmount)
				.flatPrice(flatPrice)
				.flatUsedElectricity(flatUsedElectricity)
				.flatPlanLossElectricity(flatPlanLossElectricity)
				.flatAmount(flatAmount)
				.valleyPrice(valleyPrice)
				.valleyUsedElectricity(valleyUsedElectricity)
				.valleyPlanLossElectricity(valleyPlanLossElectricity)
				.valleyAmount(valleyAmount)
				.ammeterTotalStart(ammeterTotalStart)
				.ammeterTotalEnd(ammeterTotalEnd)
				.totalElectricity(totalElectricity)
				.planLossTotalElectricity(planLossTotalElectricity)
				.consumptionAmount(consumptionAmount)
				.vinCode(vinCode)
				.transactionIdentifier(transactionIdentifier)
				.transactionTime(transactionTime)
				.stopReasonMsg(stopReasonMsg)
				.logicCard(logicCard)
				.build();

		// 保存报文
		String jsonMsg = JSONObject.toJSONString(data);
		pileMsgRecordService.save(pileSn, pileSn + connectorCode, type, jsonMsg, ykcDataProtocol.getHEXString());

		// 处理订单加锁
		String lockKey = "settle_order_" + transactionCode;
		String uuid = IdUtils.fastUUID();
		try {
			// redis锁
			Boolean isLock = redisCache.lock(lockKey, uuid, 1500);
			if (isLock) {
				processOrder(data);
			}
		} catch (Exception e) {
			log.error("处理订单发生异常", e);
		} finally {
			if (uuid.equals(redisCache.getCacheObject(lockKey).toString())) {
				redisCache.unLock(lockKey);
			}
		}

		

		/*
		应答
		确认结果  0x00 上传成功 0x01 非法账单
		2022年12月15日11点28分发现返回 01非法账单，充电桩会持续上传交易记录，后面产生的交易记录被阻塞
		 */
		byte[] confirmResultBytes = Constants.zeroByteArray;
		byte[] concatMsgBody = Bytes.concat(orderCodeByteArr, confirmResultBytes);

		return getResult(ykcDataProtocol, concatMsgBody);
	}

	private void processOrder(TransactionRecordsData data) {
		String transactionCode = data.getTransactionCode();
		// 根据交易流水号查询订单信息
		OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByTransactionCode(transactionCode);
		if (orderBasicInfo != null) {
			// 平台存在订单
			orderBasicInfo.setReason(data.getStopReasonMsg());
			// 如果订单状态为 异常，则改为 待结算
			if (StringUtils.equals(OrderStatusEnum.ABNORMAL.getValue(), orderBasicInfo.getOrderStatus())) {
				orderBasicInfo.setOrderStatus(OrderStatusEnum.STAY_SETTLEMENT.getValue());
			}
			// 校验一下开始时间和结束时间，防止充电中桩离线，时间不准确
			if (Objects.isNull(orderBasicInfo.getChargeStartTime())) { // 开始时间
				orderBasicInfo.setChargeStartTime(DateUtils.parseDate(data.getStartTime()));
			}
			if (Objects.isNull(orderBasicInfo.getChargeEndTime())) { // 结束时间
				orderBasicInfo.setChargeEndTime(DateUtils.parseDate(data.getEndTime()));
			}
			if (!StringUtils.equals("0000000000000000", data.getLogicCard())) {
				// 根据物理卡号查出当前为锁定状态的卡
				PileAuthCard cardInfo = pileAuthCardService.selectSomeStatusCardInfo(CardStatusEnum.START_LOCK.getCode(), orderBasicInfo.getLogicCard());
				if (cardInfo != null) {
					// orderBasicInfo.setMemberId(cardInfo.getMemberId());
					// 将此卡状态改为正常
					cardInfo.setStatus(CardStatusEnum.NORMAL.getCode());
					pileAuthCardService.updatePileAuthCard(cardInfo);
				}
			}
			// 如果是vin启动，将启动锁定状态改为正常
			if (StringUtils.equals(data.getTransactionIdentifier(), "05")) {
				MemberPlateNumberRelation plateInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(data.getVinCode());
				if (plateInfo != null && (StringUtils.equals(plateInfo.getVinStatus(), "2"))) {
					plateInfo.setVinStatus("1");
					memberPlateNumberRelationService.updateMemberPlateNumberRelation(plateInfo);
				}
			}
			orderBasicInfoService.updateOrderBasicInfo(orderBasicInfo);

			// 结算订单操作
			try {
				orderBasicInfoService.settleOrder(data, orderBasicInfo);
			} catch (Exception e) {
				log.error("结算订单发生异常", e);
			}

			try {
				// 联联平台 推送订单信息  notification_orderInfo
				// 查询该站点是否推送联联平台
				StationSettingRelation relation = new StationSettingRelation();
				relation.setStationId(Long.parseLong(orderBasicInfo.getStationId()));
				StationSettingRelationVO relationInfo = stationSettingRelationService.selectRelationInfo(relation);
				// ThirdPartySettingInfo infoByStationId = thirdPartySettingInfoService.getInfoByStationId(Long.parseLong(stationId));
				if (Objects.nonNull(relationInfo)) {
					// 推送订单信息
					lianLianService.pushOrderInfo(orderBasicInfo.getOrderCode());
					// 推送充电订单信息
					lianLianService.pushChargeOrderInfo(orderBasicInfo.getOrderCode());
				}
				// 调用相关接口
			} catch (Exception e) {
				log.error("联联平台 推送订单信息发生异常", e);
			}
		} else {
			// 平台没有查到订单
			orderBasicInfoService.saveAbnormalOrder(data);
			log.warn("充电桩传来的交易记录，根据交易流水号:{}查询不到订单，判定为可疑账单", transactionCode);
		}
	}
}
