package com.wsm.admin.handle;

import com.alibaba.fastjson.JSONObject;
import com.wsm.admin.model.Device;
import com.wsm.admin.model.DeviceStatus;
import com.wsm.admin.service.IDeviceService;
import com.wsm.admin.service.IDeviceStatusService;
import com.wsm.admin.service.impl.DeviceServiceImpl;
import com.wsm.admin.service.impl.DeviceStatusServiceImpl;
import com.wsm.common.util.DeviceUtil;
import com.wsm.common.util.ByteUtil;
import com.wsm.common.util.SpringContext;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.simp.SimpMessagingTemplate;

import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static java.lang.Long.parseLong;

/**
 * 接受UDP消息并且处理
 *
 */
public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {

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

    private IDeviceStatusService deviceStatusService;
    private IDeviceService deviceService;
    private SimpMessagingTemplate messagingTemplate;

    public UdpServerHandler(){
        if (deviceService == null){
            deviceService = SpringContext.getBean(DeviceServiceImpl.class);
        }
        if (deviceStatusService == null){
            deviceStatusService = SpringContext.getBean(DeviceStatusServiceImpl.class);
        }
        if (messagingTemplate == null){
            messagingTemplate = SpringContext.getBean(SimpMessagingTemplate.class);
        }
    }

    private static final Map<String, String> jgDeviceStatusMap = new HashMap<>();

    static {
        jgDeviceStatusMap.put("ERC52", "水浸事件");
        jgDeviceStatusMap.put("ERC51", "井盖掀翻");
        jgDeviceStatusMap.put("ERC50", "井盖倾斜/抬起");
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
        ByteBuf buf = packet.copy().content();
        //通过ByteBuf的readableBytes方法可以获取缓冲区可读的字节数，
        //根据可读的字节数创建byte数组
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String receiveMsg = ByteUtil.bytesToHexString(req).toUpperCase();
        log.warn("Received UDP Msg :" + receiveMsg);

        if (StringUtils.isNotEmpty(receiveMsg)){
            String feedback = handleJG(receiveMsg);
            // 由于数据报的数据是以字符数组传的形式存储的，所以传转数据
            byte[] bytes = feedback.getBytes("UTF-8");
            //在这里可以返回一个UDP消息给对方
            ctx.write(new DatagramPacket(Unpooled.copiedBuffer(bytes), packet.sender()));
        }else{
            log.error("Received Error UDP Message:" + receiveMsg);
        }
    }

    private String handleJG(String receiveMsg) {
        StringBuffer feedback = new StringBuffer("68");
        StringBuffer lStr = new StringBuffer("4B");

        log.warn("======接收到井盖传感器推送信息======");
        String[] str = DeviceUtil.turnToArray(receiveMsg);
        String afn  = str[12];
        String fn = str[14]+str[15]+str[16]+str[17];
        String frameNumber = str[13];
//        log.warn("afn:"+afn);
//        log.warn("fn:"+fn);
//        log.warn("倒数第一个字符:"+str[str.length-1]);
//        log.warn("倒数第二个字符:"+str[str.length-2]);

        String deviceId = DeviceUtil.getJGDeviceID(str);
        log.warn("设备号:"+deviceId);

        lStr.append(DeviceUtil.getFeedBackJGDeviceID(str)).append("04").append(afn).append(frameNumber).append(fn);
        String body = receiveMsg.substring(36, receiveMsg.length()-4);
        String[] bodyStr = DeviceUtil.turnToArray(body);
        log.warn("数据体是：" + body);

        if (StringUtils.isNotEmpty(body)){
            StringBuffer feedbackBody = new StringBuffer();
            feedbackBody.append("00").append("00").append("EE").append("32131031C318").append("00000000000000000000000000000000000000")
                    .append("EE").append("C0").append("A8").append("01").append("E1").append("2008").append("EE").append(DeviceUtil.getFeedBackJGDeviceID(str))
                    .append("55").append("00000000").append("EE").append("1008").append("00000000000000000000");
            lStr.append(feedbackBody);

            log.warn("推送的是心跳、告警数据");
            int count = (int) parseLong(bodyStr[0], 10);
            log.warn("总共是："+count + "个事件");

            for (int i = 0, length = 26; i < count; i++){
                log.warn("=======第"+(i+1)+"个事件=======");
                String eventStr = body.substring(8 + i*length, (8 + i*length)+26);
                log.warn("======="+eventStr +"=======");
                String[] eventStrArr = DeviceUtil.turnToArray(eventStr);
                String type = "ERC" + parseLong(eventStrArr[0], 16);
                if (jgDeviceStatusMap.get(type) != null){
                    log.warn("======="+jgDeviceStatusMap.get(type)+"=======\n");

                    String dateStr = eventStrArr[6]+eventStrArr[5]+eventStrArr[4]+eventStrArr[3]+eventStrArr[2];
                    DateTime dateTime = DateTime.parse(dateStr, DateTimeFormat.forPattern("yyMMddHHmm"));

                    log.warn("=======时间"+dateTime.toDate()+"=======\n");

                    Device device = deviceService.findByDeviceId(deviceId);
                    if (device != null){
                        DeviceStatus status =  new DeviceStatus();
                        status.setContent(jgDeviceStatusMap.get(type));
                        status.setDevice(device);
                        status.setStatus((byte)1);
                        status.setCreateTime(dateTime.toDate());
                        status.setUpdateTime(dateTime.toDate());
                        deviceStatusService.save(status);
                        log.warn(device.getDeviceId() + ":"+ status.getContent());

                        JSONObject result = new JSONObject();
                        result.put("id", device.getDeviceId());
                        result.put("deviceType", device.getDeviceType());
                        result.put("status", "ERC"+type);
                        messagingTemplate.convertAndSend("/topic/device", result.toJSONString());
                    }
                }
            }
        }else{
            log.warn("推送的是上报完毕报文");
        }
        StringBuffer a = new StringBuffer(ByteUtil.toBinary(lStr.toString().length()/2)).append("10");
        StringBuffer zero = new StringBuffer();
        for (int i = 0; i < 16-a.length(); i++){
            zero.append("0");
        }
        zero.append(a);
        String ab = ByteUtil.binaryString2hexString(zero.toString());
        String[] abArr = DeviceUtil.turnToArray(ab);
        feedback.append(abArr[1]).append(abArr[0]).append(abArr[1]).append(abArr[0]).append("68");
        lStr.append(ByteUtil.makeChecksum(lStr.toString()));
        lStr.append("16");
        feedback.append(lStr);
        return feedback.toString().toUpperCase();
    }



    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        // We don't close the channel because we can keep serving requests.
    }

    public Timestamp getTime(){
        Date date = new Date();
        Timestamp time = new Timestamp(date.getTime());
        return time;
    }

}