package com.zd.netty.sdk;

import com.gg.reader.api.dal.GClient;
import com.gg.reader.api.dal.GServer;
import com.gg.reader.api.protocol.gx.MsgBaseInventoryEpc;
import com.gg.reader.api.protocol.gx.MsgBaseSetBaseband;
import com.gg.reader.api.protocol.gx.MsgBaseSetPower;
import com.zd.common.core.enums.HardwareOperate;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.SpringUtils;
import com.zd.netty.service.IService;
import com.zd.system.api.laboratory.RemoteLaboratoryService;
import com.zd.system.api.laboratory.domain.RemoteLabHardware;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * @author Administrator
 */
@Slf4j
@Service
public class DeJuRFIDClientImpl implements IService {

    private final Map<String, GServer> serverMap = new ConcurrentHashMap<>();
    @Resource
    private RemoteLaboratoryService remoteLaboratoryService;
    @Resource
    private DeJuRFIDServerImpl service;

    @Resource
    private RedisTemplate<String,RemoteLabHardware> redisTemplate;

    private static final ScheduledExecutorService scheduledExecutorService = SpringUtils.getBean("scheduledExecutorService");

    @Override
    public void start(RemoteLabHardware hardware) {
        String ipAddress = hardware.getIpAddress();
        GServer server;
        if (serverMap.containsKey(ipAddress)) {
            server = serverMap.get(ipAddress);
            boolean listen = server.isListend();
            if (listen) {
                server.close();
            }
        } else {
            server = new GServer();
            serverMap.put(ipAddress, server);
        }
        String[] ip = ipAddress.split(":");
        int port=8160;
        if (ip.length>1){
            port= Integer.parseInt(ip[1]);
        }
        if (server.open(port)) {
            log.info("开始监听："+ipAddress);
            subscribeServerHandler(server, hardware);
        } else {
            log.info("监听失败:"+ipAddress);
            throw new ServiceException("监听失败,请稍后进行设备重连。。。");
        }
    }

    @Override
    public void disconnect(RemoteLabHardware hardware) {
        String ipAddress = hardware.getIpAddress();
        if (serverMap.containsKey(ipAddress)) {
            GServer server = serverMap.get(ipAddress);
            service.close(hardware);
            server.close();
            serverMap.remove(ipAddress);
            log.info(ipAddress + "---监听结束");
        }
    }

    @Override
    public boolean alarm(RemoteLabHardware hardware) {
        return service.alarm(hardware);
    }

    /**
     * 订阅监听上报
     *
     * @param server   服务对象
     * @param hardware 设备对象
     */
    public void subscribeServerHandler(GServer server, RemoteLabHardware hardware) {
        server.onGClientConnected = (client, serialNumber) -> {
            redisTemplate.opsForValue().set(client.getSerialNumber(),hardware);
            client.setSendHeartBeat(true);//开启心跳检测Tcp连接状态
            subscribeTcpHandler(client);//订阅Tcp断连上报
            client.setPrint(true);
            reSet(hardware, client);
            service.subscribeHandler(client, hardware);
            subscribeHandlerTagEpcOver(client);
            remoteLaboratoryService.update(HardwareOperate.OPEN, hardware.getIpAddress());
            log.info(client.getName() + "---监听成功");
        };
    }

    /**
     * 订阅6c标签信息上报停止事件
     *
     * @param client   客户端
     */
    public void subscribeHandlerTagEpcOver(GClient client) {
        client.onTagEpcOver= (s, logBaseEpcInfo) -> {
            log.info("HandlerTagEpcOver:"+s);
            RemoteLabHardware labHardware = redisTemplate.opsForValue().get(client.getSerialNumber());
            if (labHardware==null){
                return;
            }
            disconnect(labHardware);
            start(labHardware);
        };
    }

    private void reSet(RemoteLabHardware hardware, GClient client) {
        MsgBaseSetBaseband msgBaseSetBaseband = DeJuRFIDServerImpl.setSession(hardware, client);
        if (0 != msgBaseSetBaseband.getRtCode()) {
            log.error("Session configuration error.");
            reConnect(hardware, client);
            return;
        }
        MsgBaseSetPower msgBaseSetPower = DeJuRFIDServerImpl.setPower(hardware, client);
        if (0 != msgBaseSetPower.getRtCode()) {
            log.error("Power configuration error.");
            reConnect(hardware, client);
            return;
        }
        MsgBaseInventoryEpc msgBaseInventoryEpc = DeJuRFIDServerImpl.setInventory(hardware, client);
        if (0 != msgBaseInventoryEpc.getRtCode()) {
            log.error("Inventory epc error.");
            reConnect(hardware, client);
            return;
        }
        boolean changeGpi = DeJuRFIDServerImpl.setGpi(client);
        if (!changeGpi){
            reConnect(hardware,client);
        }
    }

    private void reConnect(RemoteLabHardware hardware, GClient client) {
        DeJuRFIDServerImpl.stopMsg(client);
        reSet(hardware, client);
    }

    /**
     * 订阅TCP断开连接上报
     *
     * @param client   客户端对象
     */
    private void subscribeTcpHandler(GClient client) {
        RemoteLabHardware labHardware = redisTemplate.opsForValue().get(client.getSerialNumber());
        client.onDisconnected = s -> {
            log.info("连接" + s + "已断开");
            if (labHardware!=null){
                disconnect(labHardware);
                remoteLaboratoryService.update(HardwareOperate.CLOSE, labHardware.getIpAddress());
                log.info("连接" + s + "重连中。。。");
                scheduledExecutorService.schedule(()-> start(labHardware),30, TimeUnit.SECONDS);
            }
        };
    }
}
