package com.mvc.netty;

import com.mvc.constant.DeviceUpgradeStatus;
import com.mvc.constant.UpgradeSpecification;
import com.mvc.entity.TPackLog;
import com.mvc.entity.TaskReviewPush;
import com.mvc.forwarmana.PackUtils;
import com.mvc.iot.IotStoreBlockingQueue;
import com.mvc.iot.model.IotTempModel;
import com.mvc.model.TAireadModel;
import com.mvc.model.TaskSpecialCfgModel;
import com.mvc.model.upgrade.TUpgradePackageModel;
import com.mvc.model.upgrade.TUpgradePlanDetailModel;
import com.mvc.model.upgrade.TUpgradePlanModel;
import com.mvc.model.upgrade.TUpgradeResultsModel;
import com.mvc.netty.dealconstant.HandleMsgCode;
import com.mvc.netty.dealconstant.MsgIdentifier;
import com.mvc.netty.dealconstant.UpgradeIdentifier;
import com.mvc.netty.xmodem.ControlChar;
import com.mvc.netty.xmodem.XModemService;
import com.mvc.service.aiiden.TaskReviewPushService;
import com.mvc.service.copy.TPackLogService;
import com.mvc.service.taizhang.TTaskDownService;
import com.mvc.service.taizhang.TaskSpecialCfgService;
import com.mvc.service.upgrade.TUpgradePackageService;
import com.mvc.service.upgrade.TUpgradePlanDetailService;
import com.mvc.service.upgrade.TUpgradePlanService;
import com.mvc.task.SocketProperties;
import com.mvc.utils.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.*;

@Sharable
@Component
public class WmNettyServerHandler_2 extends ChannelInboundHandlerAdapter {

    private static Logger log = LoggerFactory.getLogger(WmNettyServerHandler_2.class);

    @Resource
    private SimpleResponse simpleResponse;

    @Resource
    private TTaskDownService tTaskDownService;

    @Resource
    private TaskReviewPushService taskReviewPushService;

    @Resource
    private TPackLogService tPackLogService;

    @Resource
    private XModemService xModemService;

    @Resource
    private SocketProperties properties;

    @Resource
    private PackageParse packageParse;

    @Resource
    private TUpgradePlanService tUpgradePlanService;

    @Resource
    private VersionMessageParser versionMessageParser;

    @Resource
    private TUpgradePlanDetailService upgradePlanDetailService;

    @Resource
    private TaskSpecialCfgService taskSpecialCfgService;

    @Resource
    private TUpgradePackageService upgradePackageService;

    //升级限定电压,低于此值不升级 2024-04-15 guozhao
    private static final double UPGRADE_LIMITED_VOLTAGE = 3.4;

    /**
     * 报文读取解析
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;

        log.info("[" + ctx.channel().remoteAddress().toString() + "]:----------开始接收报文----------");

        byte[] dataArr = null;
        if (!buf.hasArray()) {
            int length = buf.readableBytes();
            dataArr = new byte[length];
            buf.getBytes(buf.readerIndex(), dataArr);
        } else {
            dataArr = buf.array();
        }
        buf.release();              //释放内存(观察)              2022-08-17 guozhao

        String resStr = NumberUtil.bytesToHexStr(dataArr);

        log.info("[" + ctx.channel().remoteAddress().toString() + "]:" + resStr);

        ControlChar controlChar = xModemService.readControlChar(dataArr);
        if (controlChar == null) {
            handleDataMessage(ctx, resStr);
        } else {//处理XModem报文
            xModemService.analysisXModemData(ctx, dataArr);
        }
    }

    /**
     * 处理数据报文
     *
     * @param ctx
     * @param resStr
     * @throws InterruptedException
     */
    private void handleDataMessage(ChannelHandlerContext ctx, String resStr) throws InterruptedException {
        Date now = new Date();
        InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();

        HashMap<Integer, FzBaowenModel> localMap = ThreadLocalUtils.threadLocal.get();
        FzBaowenModel baowenModel = localMap.get(ctx.hashCode());
        if (baowenModel == null) {
            baowenModel = new FzBaowenModel();
            baowenModel.getTotalmsg().append(resStr);
            baowenModel.setCurrentmsg(resStr);
            //RandomCode:channel.id + 客户端IP(ip前有一个/):客户端端口- 2022-11-09 guozhao
            String randomCode = ctx.channel().id() + "" + address.getAddress() + ":" + address.getPort();
            baowenModel.setRandomCode(randomCode);
            baowenModel.parse();
            localMap.put(ctx.hashCode(), baowenModel);
        } else {
            if (baowenModel.getHandleMsgCode() == HandleMsgCode.H_F2) {//单独处理查任务后收到的数据 2023-01-17 guozhao
                baowenModel.setCurrentmsg(resStr);
            } else {
                baowenModel.getTotalmsg().append(resStr);
                baowenModel.setCurrentmsg(baowenModel.getCurrentmsg() + resStr);
            }
            baowenModel.parse();
        }
        baowenModel.setLastRevTime(now);//每收到一包都更新一下最后接收时间 2022-09-22 guozhao
        if (StringUtils.isNotEmpty(baowenModel.getErrorflag()) && baowenModel.getErrorflag().equals("1")) {
            return;
        }
        if (baowenModel.getType() == null) {
            //添加另一种可能 OTA升级后重启后先上报版本信息 2024-01-23 guozhao
            if (StringUtils.isNotEmpty(baowenModel.getVersionInfo())) {
                String reply = simpleResponse.generateMsgByStationCode(baowenModel.getStationcode(), HandleMsgCode.H_ED, "");
                replyMessage(ctx, reply);
                saveDownTaskPack(baowenModel.getStationcode(), reply, baowenModel.getSn());
            } else if (baowenModel.isQueryMode() || baowenModel.isBeforeTask()) {
                //如果type是空的,代表是开机后的查询交互(查ip,查任务),未定义type是防止与报文数据的type冲突 2023-01-16 guozhao
                dealQueryMessage(baowenModel, ctx);
            }
            return;
        }

        switch (baowenModel.getType()) {
            case VIRT_H_31:
                handleMsg_H31(ctx, localMap, baowenModel);
                break;
            case H_32:
                handleMsg_H32(ctx, localMap, baowenModel);
                break;
            case H_36:
            case H_E6:
            case H_E2:
                handleMsg_H36(ctx, localMap, baowenModel);
                break;
            case H_52:
                handleMsg_H52(ctx, localMap, baowenModel);
                break;
            case H_EA:
                handleMsg_HEA(ctx, localMap, baowenModel);
                break;
        }
    }

    private void handleMsg_H36(ChannelHandlerContext ctx, HashMap<Integer, FzBaowenModel> localMap, FzBaowenModel baowenModel) throws InterruptedException {
        if (baowenModel.getBaowen().size() == baowenModel.getPackCount()) {
            StoreBlockingQueue.baoweoQueue.put(baowenModel);
            localMap.remove(ctx.hashCode());
            replyNormalMsg(ctx, baowenModel.getStationcode());
        }
    }

    private void handleMsg_HEA(ChannelHandlerContext ctx, HashMap<Integer, FzBaowenModel> localMap, FzBaowenModel baowenModel) throws InterruptedException {
        StoreBlockingQueue.baoweoQueue.put(baowenModel);
        List<String> reply = tTaskDownService.generateReplyByTaskid(baowenModel.getSn(), baowenModel.getStationcode(), false);
        if (reply != null) {
            baowenModel.setTaskdownid(reply.get(0));
            sendDownTask(reply.get(1), ctx);
            return;
        } else {
            localMap.remove(ctx.hashCode());
            replyNormalMsg(ctx, baowenModel.getStationcode());
        }
    }

    private void handleMsg_H52(ChannelHandlerContext ctx, HashMap<Integer, FzBaowenModel> localMap, FzBaowenModel baowenModel) throws InterruptedException {
        StoreBlockingQueue.baoweoQueue.put(baowenModel);
        localMap.remove(ctx.hashCode());
        replyNormalMsg(ctx, baowenModel.getStationcode());
    }

    private void handleMsg_H32(ChannelHandlerContext ctx, HashMap<Integer, FzBaowenModel> localMap, FzBaowenModel baowenModel) throws InterruptedException {
        if ((baowenModel.getTaskdownid() == null || baowenModel.isBeforeTask()) && baowenModel.getBaowen().size() == baowenModel.getPackCount()) {//查找下发任务
            if (baowenModel.isPartMode() && !baowenModel.isLastPart()) {//片段模式,但不是最后一个片段
                log.info("--------------当前片段结束--------------");
                return;
            }

            if (baowenModel.isBeforeTask()) {//前置任务无需再处理任务部分 2023-01-17 guozhao
                StoreBlockingQueue.baoweoQueue.put(baowenModel);
                localMap.remove(ctx.hashCode());
                String replayMsg = replyNormalMsg(ctx, baowenModel.getStationcode());
                baowenModel.setLastReplayMsg(replayMsg);
                return;
            }

            if (baowenModel.getTaskReviewPushreplay().size() > 0) {  //没有配置回执但有审核回执的
                StoreBlockingQueue.baoweoQueue.put(baowenModel);
                localMap.remove(ctx.hashCode());
                return;
            }

            //收到专项配置的回执,本次流程结束 2024-04-24 guozhao
            if (baowenModel.getSpecialCfgModel() != null && StringUtils.isNotEmpty(baowenModel.getSpecialCfgModel().getReplyMessage())) {
                StoreBlockingQueue.baoweoQueue.put(baowenModel);
                localMap.remove(ctx.hashCode());
                return;
            }

            TaskReviewPush pushModel = taskReviewPushService.findTaskReviewPushByStationCode(baowenModel.getSn(), baowenModel.getStationcode());
            boolean isReviewPush = pushModel != null;
            log.info("查询审核任务[" + baowenModel.getStationcode() + "]." + (pushModel == null ? "0" : pushModel.getReviewValue()));
            baowenModel.setTaskReviewPush(pushModel);
            baowenModel.parseImei(packageParse);

            TaskSpecialCfgModel specialCfgModel = taskSpecialCfgService.findTaskSpecialCfgsByImei(baowenModel.getImei());

            /** 优化:当有专项配置时,不再需要查询其它任务;有升级任务时也一样,但审核任务不可后置,涉及报文结束符选择 2024-05-07 guozhao */
            //升级判断项
            TUpgradePlanModel planModel = null;
            boolean isUpgrade = false;//是否需要升级

            //召测、远程报文
            List<String> reply = null;

            if (specialCfgModel == null) {//没有专项配置才查升级任务
                planModel = tUpgradePlanService.findTUpgradePlanByDeviceSn(baowenModel.getSn(), true);
                if (planModel != null) {
                    boolean isUpgradeEligible = true;
                    //线上设备才需要校验电压等指标(回退也不校验)
                    if (planModel.getDeviceClass().equals("1") && planModel.getPlanType().equals("1")) {
                        isUpgradeEligible = checkVersionAndCSQ(baowenModel, planModel.getPackageId()) == 0;
                    }

                    isUpgrade = !checkUpgradePlan(baowenModel.getVersionInfo(), planModel) && isUpgradeEligible;
                }
            }
            if (!isUpgrade) {//不需要升级才查询配置任务
                reply = tTaskDownService.generateReplyByTaskid(baowenModel.getSn(), baowenModel.getStationcode(), isReviewPush);
            }
            /** 审核任务需要先查, */

            //根据IMEI配置设备SN任务优先(SN是所有任务的前提) 2024-04-23 guozhao
            if (specialCfgModel != null) {
                baowenModel.setSpecialCfgModel(specialCfgModel);
                String specialCfgMsg = simpleResponse.generateSpecialCfgMessage(specialCfgModel);
                replyMessage(ctx, specialCfgMsg);
                baowenModel.setLastReplayMsg(specialCfgMsg);
                savePackLog(HandleMsgCode.H_E3, baowenModel, specialCfgMsg);
                return;
            } else if (isUpgrade) {//有升级任务(且未执行成功)
                String lenFlag = PackUtils.getItemLenIdentifier(planModel.getPlanType().length(), 0);
                String playType = StringUtils.leftPad(planModel.getPlanType(), 2, '0');
                String body = UpgradeIdentifier.FF40.getKey() + lenFlag + playType;
                String replayMsg = simpleResponse.generateMsgByStationCode(baowenModel.getStationcode(), HandleMsgCode.H_EC, body);
                sendDownTask(replayMsg, ctx);
                savePackLog(HandleMsgCode.H_EC, baowenModel, replayMsg);
                baowenModel.setUpgradePlanModel(planModel);
                baowenModel.setLastReplayMsg(replayMsg);
                StoreBlockingQueue.baoweoQueue.put(baowenModel);//开始准备升级前,把定时报解析了
                if (planModel.getPlanType().equals("2")) {//版本回退,下发EC后直接计次(中间不需要传输文件)
                    tUpgradePlanService.updateExecNum(planModel, baowenModel.getSn());
                }
                return;
            } else if (reply != null) {
                baowenModel.setTaskdownid(reply.get(0));
                //log.info("有下行任务[" + baowenModel.getStationcode() + "]");
                sendDownTask(reply.get(1), ctx);
                saveDownTaskPack(baowenModel.getStationcode(), reply.get(1), baowenModel.getSn());
                baowenModel.setLastReplayMsg(reply.get(1));
                return;
            } else if (pushModel != null) {     //没有配置和召测任务,直接发审核任务
                log.info("没有下行任务,但有审核任务[" + baowenModel.getStationcode() + "]");
                String pushMsg = sendTaskReviewPushMsg(baowenModel, ctx);
                baowenModel.getTaskReviewPush().setPushRawMsg(pushMsg);
                //防止手动加记录时,未赋值num的情况(极端情况下才会出现) 2024-06-19 guozhao
                int pushNum = pushModel.getPushNum() == null ? 1 : pushModel.getPushNum() + 1;
                baowenModel.getTaskReviewPush().setPushNum(pushNum);
                return;
            } else {//无任务任务,正常回执
                StoreBlockingQueue.baoweoQueue.put(baowenModel);
                localMap.remove(ctx.hashCode());
                String replayMsg = replyNormalMsg(ctx, baowenModel.getStationcode());
                baowenModel.setLastReplayMsg(replayMsg);
            }
            /*else { //将升级任务前置 2024-05-07 guozhao
                //升级部分(链路维持报的2F->EA)
                TUpgradePlanModel planModel = tUpgradePlanService.findTUpgradePlanByDeviceSn(baowenModel.getSn(), true);
                boolean isVtOk = checkVoltage(baowenModel);
                if (planModel != null && !checkUpgradePlan(baowenModel.getVersionInfo(), planModel) && isVtOk) {//有升级任务(且未执行成功)
                    String lenFlag = PackUtils.getItemLenIdentifier(planModel.getPlanType().length(), 0);
                    String playType = StringUtils.leftPad(planModel.getPlanType(), 2, '0');
                    String body = UpgradeIdentifier.FF40.getKey() + lenFlag + playType;
                    String replayMsg = simpleResponse.generateMsgByStationCode(baowenModel.getStationcode(), HandleMsgCode.H_EC, body);
                    sendDownTask(replayMsg, ctx);
                    baowenModel.setUpgradePlanModel(planModel);
                    StoreBlockingQueue.baoweoQueue.put(baowenModel);//开始准备升级前,把定时报解析了
                    if (planModel.getPlanType().equals("2")) {//版本回退,下发EC后直接计次(中间不需要传输文件)
                        tUpgradePlanService.updateExecNum(planModel, baowenModel.getSn());
                    }
                    return;
                } else {
                    StoreBlockingQueue.baoweoQueue.put(baowenModel);
                    localMap.remove(ctx.hashCode());
                    replyNormalMsg(ctx, baowenModel.getStationcode());
                    //有升级计划,但电压不符合标准(暂不更新状态,等待设备电压恢复 2024-04-16 guozhao)
                    //updatePlanDetailStatus(baowenModel.getSn(), planModel, isVtOk);
                }
            }*/
        } else {
            if (baowenModel.getTaskReviewPushreplay().size() > 0) {  //没有配置回执但有审核回执的
                StoreBlockingQueue.baoweoQueue.put(baowenModel);
                localMap.remove(ctx.hashCode());
                return;
            } else if (baowenModel.getPeizhi().size() > 0) {
                if (baowenModel.getTaskReviewPush() == null) {
                    StoreBlockingQueue.baoweoQueue.put(baowenModel);
                    localMap.remove(ctx.hashCode());
                    return;
                } else if (baowenModel.getTaskReviewPushreplay().size() == 0) {
                    String pushMsg = sendTaskReviewPushMsg(baowenModel, ctx);
                    baowenModel.getTaskReviewPush().setPushRawMsg(pushMsg);
                    int pushNum = baowenModel.getTaskReviewPush().getPushNum() == null ? 1 : baowenModel.getTaskReviewPush().getPushNum() + 1;
                    baowenModel.getTaskReviewPush().setPushNum(pushNum);
                    return;
                }
            }else if(baowenModel.getCurrentmsg().length() == 0&&StringUtils.isNotEmpty(baowenModel.getLastReplayMsg())){//报文重复,但设备未收到指令
                log.info("设备未收到指令,重发上一条报文");
                sendDownTask(baowenModel.getLastReplayMsg(), ctx);
            }
        }
    }

    private void handleMsg_H31(ChannelHandlerContext ctx, HashMap<Integer, FzBaowenModel> localMap, FzBaowenModel baowenModel) throws InterruptedException {
        if (baowenModel.getTaskdownid() == null) {//查找下发任务
            List<String> reply = tTaskDownService.generateReplyByTaskid(baowenModel.getSn(), baowenModel.getStationcode(), false);
            if (reply != null) {
                baowenModel.setTaskdownid(reply.get(0));
                sendDownTask(reply.get(1), ctx);
                return;
            } else {//没有下发任务
                StoreBlockingQueue.baoweoQueue.put(baowenModel);
                localMap.remove(ctx.hashCode());
                replyNormalMsg(ctx, baowenModel.getStationcode());
            }
        } else {
            //升级部分(链路维持报的2F->EA)
            TUpgradePlanModel planModel = tUpgradePlanService.findTUpgradePlanByDeviceSn(baowenModel.getSn(), true);
            boolean isVtOk = checkVoltage(baowenModel);
            if (planModel != null && !checkUpgradePlan(baowenModel.getVersionInfo(), planModel) && isVtOk) {//有升级任务(且未执行成功)
                String lenFlag = PackUtils.getItemLenIdentifier(planModel.getPlanType().length(), 0);
                String playType = StringUtils.leftPad(planModel.getPlanType(), 2, '0');
                String body = UpgradeIdentifier.FF40.getKey() + lenFlag + playType;
                String replayMsg = simpleResponse.generateMsgByStationCode(baowenModel.getStationcode(), HandleMsgCode.H_EC, body);
                sendDownTask(replayMsg, ctx);
                baowenModel.setUpgradePlanModel(planModel);
                if (planModel.getPlanType().equals("2")) {//版本回退,下发EC后直接计次(中间不需要传输文件)
                    tUpgradePlanService.updateExecNum(planModel, baowenModel.getSn());
                }
                return;
            } else {
                if (baowenModel.getPeizhi().size() > 0) {
                    StoreBlockingQueue.baoweoQueue.put(baowenModel);
                    localMap.remove(ctx.hashCode());

                    //有升级计划,但电压不符合标准(暂不更新状态,等待设备电压恢复 2024-04-16 guozhao)
                    //updatePlanDetailStatus(baowenModel.getSn(), planModel, isVtOk);
                    return;
                }
            }
        }
    }

    /**
     * 处理查询指令
     *
     * @param baowenModel
     * @param ctx
     */
    private void dealQueryMessage(FzBaowenModel baowenModel, ChannelHandlerContext ctx) {
        String msg = "";
        if (baowenModel.getHandleMsgCode() == HandleMsgCode.H_F0) {
            log.info("收到查询IP指令:[" + baowenModel.getSn() + "]");
            String ip1port1 = "";//服务器暂不进行重定向114.242.31.4:11211
            String domain = "";
            TPackLog tPackLog = packageParse.parse_QueryAddressMsg(baowenModel.getCurrentmsg());
            int taskNum = -1;
            if (StringUtils.isEmpty(ip1port1) && StringUtils.isEmpty(domain)) {//IP和域名都是空,不重新定向,才需要查任务
                List<String> reply = tTaskDownService.generateReplyByTaskid(baowenModel.getSn(), baowenModel.getStationcode(), false);
                TaskReviewPush pushModel = taskReviewPushService.findTaskReviewPushByStationCode(baowenModel.getSn(), baowenModel.getStationcode());

                taskNum = reply != null && reply.size() > 1 ? 1 : taskNum;
                taskNum = pushModel != null ? taskNum++ : taskNum;
            }
            msg = simpleResponse.generateQueryAddress(tPackLog, ip1port1, domain, taskNum);
            replyMessage(ctx, msg);

        } else if (baowenModel.getHandleMsgCode() == HandleMsgCode.H_F2) {
            TaskReviewPush pushModel = taskReviewPushService.findTaskReviewPushByStationCode(baowenModel.getSn(), baowenModel.getStationcode());
            log.info("收到查询任务指令:[" + baowenModel.getSn() + "]");
            TPackLog tPackLog = packageParse.parse_QueryTaskMsg(baowenModel.getCurrentmsg());
            boolean isReviewTask = pushModel != null;//是否有审核任务
            List<String> reply = tTaskDownService.generateReplyByTaskid(baowenModel.getSn(), baowenModel.getStationcode(), isReviewTask);
            if (reply != null && reply.size() > 1) {
                baowenModel.setTaskdownid(reply.get(0));
                sendDownTask(reply.get(1), ctx);
                saveDownTaskPack(baowenModel.getStationcode(), reply.get(1), baowenModel.getSn());
            } else {//只有审核任务
                if (pushModel != null) {
                    sendTaskReviewPushMsg(baowenModel, ctx);
                } else {
                    msg = simpleResponse.generateQueryTask(tPackLog, HandleMsgCode.H_F2);
                    replyMessage(ctx, msg);
                }
            }
        } else if (baowenModel.getHandleMsgCode() == HandleMsgCode.H_E1) {
            TaskReviewPush pushModel = taskReviewPushService.findTaskReviewPushByStationCode(baowenModel.getSn(), baowenModel.getStationcode());
            if (baowenModel.getPeizhi() != null && baowenModel.getPeizhi().size() > 0) {//收到了配置回执
                log.info("收到查询任务反馈的配置信息:[" + baowenModel.getSn() + "]");
                if (pushModel != null) {
                    sendTaskReviewPushMsg(baowenModel, ctx);
                }
            }
        }
        baowenModel.setCurrentmsg("");
        baowenModel.getTotalmsg().setLength(0);
    }

    /**
     * 回复常规报文
     *
     * @param ctx
     * @param stationCode
     */
    private String replyNormalMsg(ChannelHandlerContext ctx, String stationCode) {
        String response = simpleResponse.generateByStationCode(stationCode);
        log.info("[" + ctx.channel().remoteAddress().toString() + "]:------服务器应答----" + response);
        int len = replyMessage(ctx, response);

        //存储回执报文 2022-10-18 guozhao
        TPackLog tPackLog = new TPackLog();
        tPackLog.setStationCode(stationCode);
        tPackLog.setOriginmessage(response);
        tPackLog.setRptLen(len);
        tPackLog.setUpordown("8");
        tPackLog.setPackIndex(1);
        tPackLog.setPackCount(1);
        tPackLog.setPackId(StringUtil.getUuid());
        tPackLog.setPackGid(tPackLog.getPackId());
        tPackLog.setMultiPackFlag("0");
        tPackLog.setFlag("1");
        tPackLog.setFunCode(HandleMsgCode.H_32.getResponse());
        tPackLog.setFunName("回执报文");
        tPackLog.setRptTime(new Date());
        tPackLogService.savePackLog(tPackLog, new Date());

        return response;
    }

    private int replyMessage(ChannelHandlerContext ctx, String msg) {
        log.info("[" + ctx.channel().remoteAddress().toString() + "]:------下行报文----" + msg);
        byte[] resBytes = NumberUtil.hexStringToBytes(msg);
        ByteBuffer writeBuffer = ByteBuffer.allocate(resBytes.length);
        writeBuffer.put(resBytes);
        writeBuffer.flip();
        writeBuffer.rewind();
        ByteBuf buff = Unpooled.copiedBuffer(writeBuffer);
        ChannelFuture future = ctx.writeAndFlush(buff);
        future.addListener((ChannelFutureListener) future1 -> {
            if (future1.isSuccess()) {
                // 数据发送成功(注意,这里只代表是否成功写入缓存区,并不说明客户端接收成功)
                log.info("TCP缓存写入成功={}:{},isActive={}", ctx.channel().remoteAddress().toString(), msg, ctx.channel().isActive());
            } else {
                // 数据发送失败
                Throwable cause = future1.cause();
                cause.printStackTrace();
                log.info("TCP缓存写入失败={}:{},isActive={}", ctx.channel().remoteAddress().toString(), msg, ctx.channel().isActive());
            }
        });
        writeBuffer.clear();
        return resBytes.length;
    }

    /**
     * 异常处理
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        //log.error("[" + ctx.channel().remoteAddress().toString() + "]:发生异常数据读取失败。。。。", cause);
        //经过观察基本都是“远程主机强迫关闭了一个现有的连接”,暂不打印错误明细了 2024-03-20 guozhao
        log.error("[" + ctx.channel().remoteAddress().toString() + "]:发生异常数据读取失败。。。。");
        ctx.close();
    }

    public void sendDownTask(String taskcontent, ChannelHandlerContext ctx) {
        //下发任务数据
        try {
            replyMessage(ctx, taskcontent);
        } catch (Exception ex) {
            log.error(ex.getMessage());
        }
    }

    /**
     * 保存下行报文(简单保存,非全部信息,此类返的信息,已经是串了,需要改改造其它类)
     *
     * @param stationCode
     * @param msg
     * @param deviceSn    设备SN(补充,减弱站码依赖)
     */
    private void saveDownTaskPack(String stationCode, String msg, String deviceSn) {
        Date now = new Date();
        TPackLog tPackLog = new TPackLog();
        tPackLog.setStationCode(stationCode);
        tPackLog.setDeviceSn(deviceSn);
        tPackLog.setOriginmessage(msg);
        tPackLog.setPackIndex(1);
        tPackLog.setPackCount(1);
        String funCode = msg.substring(20, 22).toLowerCase();
        String funName = "下行任务";
        if (funCode.equals(HandleMsgCode.H_E0.getCode())) {
            funName = HandleMsgCode.H_E0.getDesc();
        } else if (funCode.equals(HandleMsgCode.H_E1.getCode())) {
            funName = HandleMsgCode.H_E1.getDesc();
            funCode = "ef";//此处转换了功能码,是为了区分召测和配置回执(功能码都是e1) 2022.10.11 guozhao
        }

        tPackLog.setFunCode(funCode);
        tPackLog.setFunName(funName);
        tPackLog.setFlag("81");
        tPackLog.setUpordown("8");
        tPackLog.setPackId(StringUtil.getUuid());
        tPackLog.setPackGid(tPackLog.getPackId());
        tPackLog.setRptTime(now);
        tPackLog.setDatatime(now);
        tPackLog.setRevTime(now);
        tPackLog.setRptLen(msg.length() / 2);
        tPackLogService.savePackLog(tPackLog, tPackLog.getRevTime());
        //tPackLogMapper.insert(tPackLog);
    }

    //客户端断开事件，可以通过此事件进行数据处理
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("[" + ctx.channel().remoteAddress().toString() + "]:Channel连接断开0--------------");

        if (((InetSocketAddress) ctx.channel().localAddress()).getPort() != properties.getPort()) {
            return;
        }

        HashMap<Integer, FzBaowenModel> localMap = ThreadLocalUtils.threadLocal.get();
        FzBaowenModel fzBaowenModel = localMap.get(ctx.hashCode());
        if (fzBaowenModel != null) {
            boolean isProcessed = false;

            if ("1".equals(fzBaowenModel.getErrorflag())) {
                StoreBlockingQueue.errorQueue.put(fzBaowenModel);
                isProcessed = true;
            } else if (fzBaowenModel.getType() == HandleMsgCode.VIRT_H_31) {
                if (fzBaowenModel.getTaskdownid() != null && fzBaowenModel.getPeizhi().size() == 0) {
                    StoreBlockingQueue.baoweoQueue.put(fzBaowenModel);
                    isProcessed = true;
                }
            } else if (fzBaowenModel.getType() == HandleMsgCode.H_32) {
                if (fzBaowenModel.getUpgradePlanModel() != null) {//有升级任务时,在进入XModem流程前就已处理
                    isProcessed = true;
                } else if (((fzBaowenModel.getTaskdownid() != null && fzBaowenModel.getPeizhi().size() == 0) || fzBaowenModel.isBeforeTask()) && fzBaowenModel.getPackCount() == fzBaowenModel.getBaowen().size()) {
                    StoreBlockingQueue.baoweoQueue.put(fzBaowenModel);
                    isProcessed = true;
                }
            } else if (fzBaowenModel.getCurrentmsg() != null && fzBaowenModel.getCurrentmsg().length() > 0) {//最终统一错误处理
                StoreBlockingQueue.errorQueue.put(fzBaowenModel);
                isProcessed = true;
            }

            //上面这些条件,只有一包时,是不会符合条件的,会造成报文不会存储 2022-10-18 guozhao
            if (!isProcessed) {
                if (fzBaowenModel.getTaskReviewPush() != null && StringUtils.isEmpty(fzBaowenModel.getErrorflag())
                        && fzBaowenModel.getPackCount() == fzBaowenModel.getBaowen().size()) {
                    //如果下发了审核值报文,但终端没有应答,会导致此报文不解析 2023-08-28 guozhao
                    StoreBlockingQueue.baoweoQueue.put(fzBaowenModel);
                } else if(StringUtils.isNotEmpty(fzBaowenModel.getVersionInfo())){//只收到了版本信息 2024-09-24 guozhao
                    StoreBlockingQueue.baoweoQueue.put(fzBaowenModel);
                } else {
                    StoreBlockingQueue.errorQueue.put(fzBaowenModel);
                }
            }

            localMap.remove(ctx.hashCode());
        }
        log.info("[" + ctx.channel().remoteAddress().toString() + "]:Channel连接断开1--------------");
    }

    /**
     * 发送审核值报文
     *
     * @param model
     * @param ctx
     */
    private String sendTaskReviewPushMsg(FzBaowenModel model, ChannelHandlerContext ctx) {
        TaskReviewPush pushModel = taskReviewPushService.findTaskReviewPushByStationCode(model.getSn(), model.getStationcode());
        if (pushModel != null) {
            String msg = simpleResponse.generatefor_TaskReviewPushMsg(pushModel);
            if (StringUtils.isEmpty(msg)) return null;
            try {
                log.info("[" + ctx.channel().remoteAddress().toString() + "]:------发送审核值报文----" + msg);
                int msgLen = replyMessage(ctx, msg);
                saveTaskReviewPushPackLog(model, msg, msgLen);
                model.setLastReplayMsg(msg);
                return msg;
            } catch (Exception ex) {
                log.error(ex.getMessage());
            }
        }
        return null;
    }

    /**
     * 保存下行审核任务的报文日志
     *
     * @param model
     */
    private void saveTaskReviewPushPackLog(FzBaowenModel model, String msg, int rptLen) {
        TPackLog tPackLog = new TPackLog();
        tPackLog.setStationCode(model.getStationcode());
        tPackLog.setOriginmessage(msg);
        tPackLog.setPackIndex(1);
        tPackLog.setPackCount(1);
        tPackLog.setFunCode("e4");
        tPackLog.setFunName("审核下发");
        tPackLog.setFlag("1");
        tPackLog.setUpordown("8");
        tPackLog.setPackId(StringUtil.getUuid());
        tPackLog.setPackGid(tPackLog.getPackId());
        tPackLog.setRptTime(new Date());
        tPackLog.setDatatime(new Date());
        tPackLog.setRptLen(rptLen);
        tPackLogService.savePackLog(tPackLog,new Date());
    }

    private void savePackLog(HandleMsgCode msgCode, FzBaowenModel model, String msg) {
        TPackLog tPackLog = new TPackLog();
        tPackLog.setStationCode(model.getStationcode());
        tPackLog.setDeviceSn(model.getSn());
        tPackLog.setOriginmessage(msg);
        tPackLog.setPackIndex(1);
        tPackLog.setPackCount(1);
        tPackLog.setFunCode(msgCode.getCode());
        tPackLog.setFunName(msgCode.getDesc());
        tPackLog.setFlag("1");
        tPackLog.setUpordown("8");
        tPackLog.setPackId(StringUtil.getUuid());
        tPackLog.setPackGid(tPackLog.getPackId());
        tPackLog.setRptTime(new Date());
        tPackLog.setDatatime(new Date());
        tPackLog.setRptLen(msg.length() / 2);
        tPackLogService.savePackLog(tPackLog, tPackLog.getRevTime());
    }

    /**
     * 校验升级计划
     * 设备升级后先发ED报版本,校验成功后,就不再发升级通知了
     *
     * @param versionInfo
     * @param upgradePlanModel
     * @return
     */
    private boolean checkUpgradePlan(String versionInfo, TUpgradePlanModel upgradePlanModel) {
        if (StringUtils.isEmpty(versionInfo)) {//未收到ED,或首次下发升级指令
            return false;
        }
        TPackLog packLog = packageParse.parse_VersionInfo(versionInfo);
        TUpgradeResultsModel resultsModel = versionMessageParser.parse(packLog.getMessage());

        //如果升级包记录被删除了,不再下发 2024-02-02 guozhao
        if (upgradePlanModel.getPackageModel() == null) {
            return true;
        }

        return upgradePlanModel.getPackageModel().getVersionNum().equalsIgnoreCase(resultsModel.getVersionNum());
    }

    /**
     * 校验电压
     *
     * @param model
     * @return
     */
    private boolean checkVoltage(FzBaowenModel model) {
        if (model.getBaowen().size() == 0) {
            return false;
        }
        TPackLog tlog = packageParse.parse_duobao(model.getBaowen().get(0));
        String msg = tlog.getMessage();

        String value = "";
        List<String> keys = MsgIdentifier.keys();
        boolean isMatch = false;
        boolean isFindVoltage = false;
        while (msg.length() > 0 && !isFindVoltage) {
            for (String key : keys) {
                if (!msg.toUpperCase().startsWith(key)) {
                    continue;
                }

                MsgIdentifier identifier = MsgIdentifier.getElement(key);
                if (identifier == null) {
                    continue;
                }
                if (identifier == MsgIdentifier.I_38) {
                    msg = identifier.parse(msg);
                    value = identifier.getValue();
                    isFindVoltage = true;
                    break;
                } else if (identifier == MsgIdentifier.FF39) {
                    msg = identifier.parse(msg);
                    value = identifier.getValue();
                    isFindVoltage = true;
                    break;
                } else {
                    msg = identifier.parse(msg);
                }
                isMatch = true;
            }
            if (!isMatch) {//报文中未匹配的合法引导符
                break;
            }
        }

        if (isFindVoltage) {
            double voltage = Double.parseDouble(value);
            return voltage >= UPGRADE_LIMITED_VOLTAGE;
        }

        return false;
    }

    private int checkVersionAndCSQ(FzBaowenModel model, int packageId) {
        if (model.getBaowen().size() == 0) {
            return -1;
        }
        TPackLog tlog = packageParse.parse_duobao(model.getBaowen().get(0));
        String msg = tlog.getMessage();

        TAireadModel aireadModel = new TAireadModel();

        String value = "";
        List<String> keys = MsgIdentifier.keys();
        boolean isMatch = false;
        int num = 0;
        while (msg.length() > 0 && num < 2) {
            for (String key : keys) {
                if (!msg.toUpperCase().startsWith(key)) {
                    continue;
                }

                MsgIdentifier identifier = MsgIdentifier.getElement(key);
                if (identifier == null) {
                    continue;
                }
                if (identifier == MsgIdentifier.I_38) {
                    msg = identifier.parse(msg);
                    value = identifier.getValue();
                    aireadModel.setVoltage(new BigDecimal(value));
                    num++;
                    isMatch = true;
                    break;
                } else if (identifier == MsgIdentifier.FF39) {
                    msg = identifier.parse(msg);
                    value = identifier.getValue();
                    aireadModel.setCsq(Integer.parseInt(value));
                    isMatch = true;
                    num++;
                    break;
                } else {
                    msg = identifier.parse(msg);
                }
                isMatch = true;
                //电压及CSQ已经找到
                if (num == 2) {
                    isMatch = true;
                    break;
                }
            }
            if (!isMatch) {//报文中未匹配的合法引导符
                return -1;
            }
        }

        TUpgradePackageModel packageModel = upgradePackageService.findTUpgradePackageById(packageId);
        UpgradeSpecification spec = UpgradeSpecification.getUpgradeSpecification(packageModel.getFileSize());
        if (spec != null) {
            if (aireadModel.getVoltage().compareTo(new BigDecimal(spec.getVoltage())) < 0) {
                return 1;
            }
            if (aireadModel.getCsq() < spec.getCsq()) {
                return 2;
            }
        }

        return 0;
    }

    /**
     * 更新计划明细状态(根据电压状态)
     *
     * @param deviceSn
     * @param planModel
     * @param isVtOk
     */
    private void updatePlanDetailStatus(String deviceSn, TUpgradePlanModel planModel, boolean isVtOk) {
        if (!isVtOk && planModel != null) {
            Optional<TUpgradePlanDetailModel> optional = planModel.getDetails().stream().filter(s -> s.getDeviceSn().equals(deviceSn)).findFirst();
            if (optional.isPresent()) {
                TUpgradePlanDetailModel detailModel = optional.get();
                detailModel.setUpgradeStatus(DeviceUpgradeStatus.LOW_VOLTAGE.getFlag());
                detailModel.setUpgradeTime(new Date());
                upgradePlanDetailService.updateTUpgradePlanDetail(detailModel);
                log.info(String.format("设备[%s]升级低电压-不升级", deviceSn));
            }
        }
    }
}
