package com.yfd.platform.component.nettyudpserver;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.modules.basedata.domain.LinkageSignal;
import com.yfd.platform.modules.basedata.domain.SubstationDevice;
import com.yfd.platform.modules.basedata.service.ILinkageSignalService;
import com.yfd.platform.modules.basedata.service.ISubstationDeviceService;
import com.yfd.platform.modules.robotapi.service.IStationRobotService;
import com.yfd.platform.utils.HttpRESTfulUtils;
import com.yfd.platform.utils.RtspToMP4;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @create 2021/9/9 10:12
 */
@Slf4j
@Component
public class NettyUdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    private static final Logger logger = LoggerFactory.getLogger(NettyUdpServer.class);
    private static final Charset CHARSET = Charset.forName("GB2312");
    private ByteBuffer buffer;

    public static NettyUdpHandler nettyServerHandler;

    @Resource
    private IStationRobotService stationRobotService;
    @Resource
    private ILinkageSignalService linkageSignalService;
    @Resource
    private HttpRESTfulUtils httpRESTfulUtils;
    @Resource
    private RtspToMP4 rtspToMP4;
    @Resource
    private ISubstationDeviceService substationDeviceService;

    @PostConstruct
    public void init() {
        nettyServerHandler = this;
        nettyServerHandler.stationRobotService = this.stationRobotService;
        nettyServerHandler.linkageSignalService = this.linkageSignalService;
        nettyServerHandler.httpRESTfulUtils = this.httpRESTfulUtils;
        nettyServerHandler.rtspToMP4 = this.rtspToMP4;
        nettyServerHandler.substationDeviceService = this.substationDeviceService;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
        logger.info("收到主辅联动信号" + ctx.toString());
        // 获取消息内容
        MyMessageProtocol msg = new MyMessageProtocol();
        ByteBuf buf = packet.content();
        byte[] startflag = new byte[5];
        buf.readBytes(startflag);
        String frametype = new String(HexUtil.encodeHex(startflag, false));
        logger.info("收到主辅联动信号" + frametype);

        //5590EB90EB
        if (frametype.equals("EB90EB9055")) {
            //接收到主辅设备联动控制信号
            log.info("接收到主辅设备联动控制信号");
            msg.setFrametype(frametype);
//            msg.setStationnum(buf.readShort());
//            msg.setMonitorindex(buf.readShort());
            msg.setStationnum(buf.readShortLE());
            msg.setMonitorindex(buf.readShortLE());
            log.info("监控索引号：" + msg.getMonitorindex() + "监控类型：" + msg.getMonitortype() + "站序号：" + msg.getStationnum() + "和校验：" + msg.getSumverify());
            LinkageSignal one =
                    nettyServerHandler.linkageSignalService.getOne(new LambdaQueryWrapper<LinkageSignal>().eq(LinkageSignal::getControlNum, msg.getMonitorindex()));
            String linkageType = one.getLinkageType();
            String linkageDeviceType = one.getLinkageDeviceType();
            if ("1".equals(linkageType) && "遥信".equals(linkageDeviceType)) {
                String deviceIdList = one.getDeviceIdList();
                List<String> split = StrUtil.split(deviceIdList, ",");
                int min = Math.min(split.size(), 3);
                for (int i = 0; i < min; i++) {
                    int finalI = i;
                    new Thread(() -> {
                        String id = split.get(finalI);
                        SubstationDevice substationDevice = nettyServerHandler.substationDeviceService.getById(id);
                        String patroldeviceJson = substationDevice.getPatroldeviceJson();
                        JSONArray jsonArray = JSONUtil.parseArray(patroldeviceJson);
                        if (jsonArray.size() > 0) {
                            JSONObject jsonObject = jsonArray.getJSONObject(0);
                            String patroldeviceCode = jsonObject.getStr("patroldevice_code");
                            String patroldeviceChannelcode = jsonObject.getStr("patroldevice_channelcode");
                            nettyServerHandler.rtspToMP4.stopRecord(patroldeviceCode + "_" + patroldeviceChannelcode);
                        }
                    }).start();

                }
                //                String id = StrUtil.subBefore(deviceIdList, ",", false);
                return;
            }
            msg.setMonitortype(buf.readByte());
            msg.setAttributelength(buf.readByte() & 0xFF);
            // 读取属性描述
            byte[] firstBytes = new byte[msg.getAttributelength()];
            buf.readBytes(firstBytes);
            String firstString = new String(firstBytes, "GB2312");
            msg.setAttribute(firstString);

            msg.setValuelength(buf.readByte() & 0xFF);
            byte[] secondBytes = new byte[msg.getValuelength()];
            buf.readBytes(secondBytes);
            String secondString = new String(secondBytes, "GB2312");
            msg.setValue(secondString);

            byte[] eventtimes = new byte[7];
            buf.readBytes(eventtimes);
            String eventtime = MyMessageProtocol.cp56ToTimeString(eventtimes);
            msg.setEventtime(eventtime);

//            short verifylength = buf.readShort();
//            Short resumlength = Short.parseShort(String.valueOf(14 + msg.getAttributelength() + msg.getValuelength()));
//
//            msg.setSumverify(verifylength);
//            if (verifylength != resumlength) {
//                throw new Exception("传输内容长度校验不一致！");
//            }
            log.info("创建一键顺控任务");
            log.info("msg" + msg);
            //调用一键顺控方法，启动顺控任务
            nettyServerHandler.linkageSignalService.createLinkSiginTask(msg);

            //4390EB90EB
        } else if (frametype.equals("EB90EB9043")) {//传输联动信号配置文件
            short stationcode = buf.readShort(); //站序号
            byte nextflag = buf.readByte(); //后续标志位
            log.info("后续标志位" + nextflag);
            short frameno = buf.readShort(); //帧序号
            log.info("帧序号" + frameno);
            int startlocation = buf.readInt(); //起始传输位置
            int framelength = buf.readByte() & 0xFF; //数据长度
            log.info("数据长度" + framelength);
            // 读取本帧数据内容
            byte[] contentBytes = new byte[framelength];
            if (frameno == 0) {
                buffer = ByteBuffer.allocate(100000000);
            }
            buf.readBytes(contentBytes);
            buffer.put(contentBytes);

            int verifylength = buf.readByte() & 0xFF;
            int resumlength = 10 + contentBytes.length;
            log.info("verifylength:" + verifylength + "resumlength:" + resumlength);
//            if (verifylength != resumlength) {
//                throw new Exception("传输内容长度校验不一致！");
//            }

            if (nextflag == 0) {
                //所有帧都读取完成
                log.info("所有帧都读取完成");
                buffer.flip();
                byte[] result = new byte[buffer.remaining()];
                buffer.get(result);
                String filecontent = new String(result, "GB2312");
                log.info(filecontent);
                // 调用后处理方法，将结果文件解析为联动信号对象数据，并保存到数据库中，
                List<LinkageSignal> linkageSignalList = analysisFileContent(filecontent);
                List<LinkageSignal> list = nettyServerHandler.linkageSignalService.list(new LambdaQueryWrapper<LinkageSignal>().select(LinkageSignal::getControlNum));
                Set<String> collect = list.stream().map(LinkageSignal::getControlNum).collect(Collectors.toSet());
                List<LinkageSignal> dataList = linkageSignalList.stream().filter(l -> !collect.contains(l.getControlNum())).collect(Collectors.toList());
                if(dataList.size()>0){
                    nettyServerHandler.linkageSignalService.saveBatch(dataList);
                }
                //todo  将联动配置文件上传到巡视主机上
            }
        }
    }

    /**********************************
     * 用途说明: 解析数据内容到联动信号数据库
     * 参数说明 filecontent
     * 返回值说明: java.util.List<com.yfd.monitor.modules.basedata.domain.LinkageSignal>
     ***********************************/
    private List<LinkageSignal> analysisFileContent(String filecontent) {
        List<LinkageSignal> linkageSignalList = new ArrayList<>();
        String regex = "\\d{4}[-]\\d{2}[-]\\d{2} \\d{2}:\\d{2}:\\d{2}";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher1 = pattern.matcher(filecontent);
        LocalDateTime now = LocalDateTime.now();
        if (matcher1.find()) {
            String group = matcher1.group();
            now = LocalDateTimeUtil.parse(group, "yyyy-MM-dd hh:mm:ss");
        }
        String regStr = "#[^\n]*\n";
        Pattern compile = Pattern.compile(regStr);
        Matcher matcher = compile.matcher(filecontent);
        while (matcher.find()) {
            LinkageSignal linkageSignal = new LinkageSignal();
            String group = matcher.group();
            String[] split = group.split("\t");
            // 站序号
            linkageSignal.setStationNum(split[1]);
            // 监控索引号
            linkageSignal.setControlNum(split[2]);
            // 设备名称
            linkageSignal.setLinkageDeviceName(split[3]);
            // 设备类型
            linkageSignal.setLinkageDeviceType(split[4]);
            // 实物ID
            linkageSignal.setMaterialId(split[5]);
            // 是否联动信号
            linkageSignal.setIsLinkageFlag(split[6]);
            linkageSignal.setTime(now);
            linkageSignal.setDatastatus("0");
            linkageSignal.setIsenable("0");
            linkageSignal.setLastmodifydate(LocalDateTime.now());
            linkageSignal.setLastmodifier("主辅联动");
            linkageSignalList.add(linkageSignal);
        }
        return linkageSignalList;
    }
}




