package com.willalp.control.netty.handler;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.willalp.common.core.domain.AjaxResult;
import com.willalp.control.netty.Tool;
import com.willalp.control.netty.model.ChannelMsgModel;
import com.willalp.control.netty.model.ControlDataModel;
import com.willalp.control.netty.model.DeviceChannelMap;
import com.willalp.device.domain.Device;
import com.willalp.device.mapper.DeviceMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * @author hs
 */
@Component
@ChannelHandler.Sharable
public class DeviceChannelHandler extends SimpleChannelInboundHandler<Object> {
    private final static Logger logger = LoggerFactory.getLogger(DeviceChannelHandler.class);

    public static DeviceChannelHandler deviceChannelHandler;

    /**
     * 超时记录
     */
    private int timeOut;

    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private ControlDataModel dataModel;

    public DeviceChannelHandler(DeviceMapper deviceMapper, ControlDataModel dataModel) {
        this.deviceMapper = deviceMapper;
        this.dataModel = dataModel;
    }

    /**
     * 因为是new出来ChannelHandler,没有托给spring容器,所以一定要先初始化,否则autowired失效
     */
    @PostConstruct
    public void init() {
        deviceChannelHandler = this;
        deviceChannelHandler.deviceMapper = this.deviceMapper;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
        timeOut = 0;
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, StandardCharsets.UTF_8);
        String remoteAddr = Tool.subRemoteAddr(ctx.channel().remoteAddress().toString());
        logger.info("IP - " + remoteAddr + " - 的消息：" + body);
        ChannelMsgModel cmm = new ChannelMsgModel();
        cmm.setChannel(ctx.channel());
        cmm.setMsg(body);
        cmm.setLastChange(new Date());
        DeviceChannelMap.add(remoteAddr, cmm);
        try {
            AjaxResult resultMap = AjaxResult.success();
            String patientPdStr = JSON.toJSONString(resultMap);
            patientPdStr += "\n";
            byte[] bytes = patientPdStr.getBytes(StandardCharsets.UTF_8);
            ByteBuf resp = Unpooled.copiedBuffer(bytes);
            DeviceChannelMap.get(remoteAddr).getChannel().writeAndFlush(resp);
            if (body.contains(",")) {
                String[] split = body.split(",");
                Device device = deviceMapper.selectOne(
                        new QueryWrapper<Device>().eq("device_no", split[0]));
                if (ObjectUtil.isNull(device)) {
                    logger.error("上电检查错误 - 未找到该设备");
                    return;
                }
                device.setDeviceIpAddr(remoteAddr);
                deviceMapper.updateById(device);
                logger.info("基站上电检查完毕 - " + split[0] + " - " + remoteAddr);
                dataModel.updateMap();
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("没有该设备");
        }
    }

    /**
     * 客户端建立新的连接时
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        timeOut = 0;
    }

    /**
     * 处理心跳检测事件的方法
     *
     * @param ctx
     * @param evt
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        IdleStateEvent event = (IdleStateEvent) evt;
        String eventDesc = null;
        switch (event.state()) {
            case READER_IDLE:
                eventDesc = "读空闲";
                break;
            case WRITER_IDLE:
                eventDesc = "写空闲";
                break;
            case ALL_IDLE:
                eventDesc = "读写空闲";
                break;
            default:
                break;
        }

        String remoteAddr = Tool.subRemoteAddr(ctx.channel().remoteAddress().toString());
        logger.info(remoteAddr + " -  " + eventDesc);
        timeOut++;
        if (timeOut > 3) {
            DeviceChannelMap.remove(remoteAddr);
            logger.info("DeviceChannelMap - 清除 - " + remoteAddr);
            logger.info("空闲次数超过三次 关闭连接");
            ctx.writeAndFlush("you are out");
            ctx.channel().close();
        }
        //super.userEventTriggered(ctx, evt);

    }

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

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        String remoteAddr = Tool.subRemoteAddr(ctx.channel().remoteAddress().toString());
        logger.info(remoteAddr + " - 断开连接");
        ctx.close();
    }

}
