package com.jpsoft.shinestar.lapi.handler;

import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.jpsoft.shinestar.lapi.dto.HeartReportInfo;
import com.jpsoft.shinestar.modules.base.service.DeviceInfoService;
import com.jpsoft.shinestar.modules.mq.manager.QueueManager;
import com.jpsoft.shinestar.modules.sys.entity.SysLog;
import com.jpsoft.shinestar.modules.sys.service.SysLogService;
import com.jpsoft.shinestar.modules.uniview.channel.LapiAttrKeys;
import com.jpsoft.shinestar.modules.uniview.channel.LapiChannel;
import com.jpsoft.shinestar.modules.uniview.service.ILapiService;
import com.jpsoft.shinestar.modules.uniview.utils.LapiSessionUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Minutes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Array;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ChannelHandler.Sharable
public class HeartReportHandler extends SimpleChannelInboundHandler<HeartReportInfo> {
    @Autowired
    private DeviceInfoService deviceInfoService;

    @Autowired
    private SysLogService sysLogService;

    @Autowired
    private ILapiService lapiService;

    @Autowired
    private QueueManager queueManager;

    private  final String X_FRAME_OPTIONS = "X-Frame-Options";
    private  final String SAMEORIGIN = "SAMEORIGIN";
    private  final String JSON_PLAIN = "application/json";
    private  final String CONTENT_LENGTH = "Content-Length";
    private  final String CONTENT_TYPE = "Content-Type";
    private  final String CONNECTION = "Connection";

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HeartReportInfo heartReportInfo) throws Exception {
        log.debug(heartReportInfo.toString());
        String ipAndPort = String.valueOf(ctx.channel().remoteAddress());
        String deviceNo = heartReportInfo.getDeviceCode();
        String ip = ipAndPort.substring(ipAndPort.indexOf("/")+1,ipAndPort.indexOf(":"));

        log.debug("收到设备心跳，deviceNo=" + deviceNo);
        log.debug("ip =="+ip);

        DateTime lastHeartTime = ctx.channel().attr(LapiAttrKeys.LAST_HEART_TIME).get();

        boolean needWrite = false;

        if(lastHeartTime==null){
            ctx.channel().attr(LapiAttrKeys.LAST_HEART_TIME).set(DateTime.now());
            needWrite = true;
        }
        else{
            int minutes = Minutes.minutesBetween(lastHeartTime,DateTime.now()).getMinutes();

            if(minutes>=10){
                ctx.channel().attr(LapiAttrKeys.LAST_HEART_TIME).set(DateTime.now());
                needWrite = true;
            }
        }

//        if(needWrite) {
//            new Thread(()->{
//                SysLog sysLog = new SysLog();
//                sysLog.setPointcut(deviceNo);
//                sysLog.setUrl("/LAPI/V1.0/PACS/Controller/HeartReportInfo");
//                sysLog.setData(heartReportInfo.toString());
//                sysLog.setRemark("设备心跳信号");
//                SocketAddress remoteAddress = ctx.channel().remoteAddress();
//                sysLog.setRemoteIp(remoteAddress.toString());
//                sysLog.setCreateTime(new Date());
//                sysLogService.insert(sysLog);
//            }).start();
//        }

        deviceInfoService.updateByDeviceNo(deviceNo,true);

        //新连接，则设置连接对应设备号
        if(ctx.channel().attr(LapiAttrKeys.DEVICE_NO).get()==null){
            ctx.channel().attr(LapiAttrKeys.DEVICE_NO).set(deviceNo);

            new Thread(()->{
                SysLog sysLog = new SysLog();
                sysLog.setPointcut(deviceNo);
                sysLog.setUrl("/LAPI/V1.0/PACS/Controller/HeartReportInfo");
                sysLog.setRemark("设备上线->设置连接对应设备编号");
                SocketAddress remoteAddress = ctx.channel().remoteAddress();
                sysLog.setRemoteIp(remoteAddress.toString());
                sysLog.setCreateTime(new Date());
                sysLogService.insert(sysLog);

                deviceInfoService.updateByDeviceNo(deviceNo,true);
            }).start();
        }

        if (!LapiSessionUtil.containsKey(deviceNo)){
            LapiChannel lapiChannel = new LapiChannel();
            lapiChannel.setChannel(ctx.channel());
            lapiChannel.setReceivePacketQueueMap(new ConcurrentHashMap<>());

            LapiSessionUtil.put(deviceNo, lapiChannel);
            queueManager.createQueue("device_" + deviceNo);

            new Thread(()->{
                SysLog sysLog = new SysLog();
                sysLog.setPointcut(deviceNo);
                sysLog.setUrl("/LAPI/V1.0/PACS/Controller/HeartReportInfo");
                sysLog.setRemark("设备上线->加入全局map");
                SocketAddress remoteAddress = ctx.channel().remoteAddress();
                sysLog.setRemoteIp(remoteAddress.toString());
                sysLog.setCreateTime(new Date());
                sysLogService.insert(sysLog);

                deviceInfoService.updateByDeviceNo(deviceNo,true);

//                String localAddress = ctx.channel().localAddress().toString();
//                String newServerAddress = "122.189.98.152";
//                String newPort = "7988";
//
//                if (localAddress.indexOf(newServerAddress)==-1){
//                    try {
//                        lapiService.updateDeviceData(Arrays.asList(deviceNo),newServerAddress,newPort);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//                else {
                //执行上线后任务
                //deviceOnlineTask.run(deviceNo);
//                }

                //设备统一设置记录上传响应
                lapiService.setLongConnectionInfo(deviceNo,1,30);
            }).start();
        }

        //返回数据
        try {
            log.debug("===心跳记录回包处理 start===");
            Map<String,Object> responseInfo  = new HashMap<>();
            Map<String,Object> dataMap  = new HashMap<>();

            dataMap.put("Time",DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));

            responseInfo.put("ResponseURL","/LAPI/V1.0/PACS/Controller/HeartReportInfo");
            responseInfo.put("Code", 0);
            responseInfo.put("Data",dataMap);

            String json = JSONUtil.toJsonStr(responseInfo);

            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(json.getBytes("UTF-8")));
            response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
            response.headers().set(CONTENT_TYPE, JSON_PLAIN);
            response.headers().set(CONNECTION, HttpHeaderValues.CLOSE);
            response.headers().set(X_FRAME_OPTIONS, SAMEORIGIN);

            ctx.channel().writeAndFlush(response);

            log.debug("===心跳记录回包处理 end===");
        }
        catch (Exception ex){
            log.error(ex.getMessage(),ex);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);

        String deviceNo = ctx.channel().attr(LapiAttrKeys.DEVICE_NO).get();

        final SysLog sysLog = new SysLog();
        sysLog.setPointcut(deviceNo);
        sysLog.setUrl("/LAPI/V1.0/PACS/Controller/HeartReportInfo");
        SocketAddress remoteAddress = ctx.channel().remoteAddress();
        sysLog.setRemoteIp(remoteAddress.toString());

        sysLog.setCreateTime(new Date());

        if(StringUtils.isNotEmpty(deviceNo)){
            log.warn(deviceNo + " channelInactive");

            //增加判断remoteAddress是否相同，避免客户端离线后，延迟通知服务端，导致服务器将新连接删除
            String remoteAddr1 = ctx.channel().remoteAddress().toString();

            if(LapiSessionUtil.containsKey(deviceNo)) {
                String remoteAddr2 = LapiSessionUtil.get(deviceNo).getChannel().remoteAddress().toString();
                sysLog.setData("当前设备对应连接->" + remoteAddr2);

                if (remoteAddr1.equals(remoteAddr2)) {
                    LapiSessionUtil.remove(deviceNo);
                    sysLog.setRemark("设备离线,已从全局map中删除");

                    new Thread(()->{
                        try {
                            //防止channelRead0和channelInactive同时发生
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        deviceInfoService.updateByDeviceNo(deviceNo,false);

                        queueManager.stopListen("device_" + deviceNo);
                    }).start();
                }
                else{
                    sysLog.setRemark("设备离线,但有新连接接入" + remoteAddr2);
                }
            }else{
                sysLog.setRemark("设备离线," + "未加入全局map");
            }

            sysLogService.insert(sysLog);
        }
    }
}
