package com.cisdi.data.AMETEKSurfaceVision;

import com.alibaba.fastjson.JSON;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionAliveCheckTask;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionChannelInitializer;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionFrameDecoder;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionIoSession;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionSessionFactory;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionSocketReturnMessage;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

/**
 * 表检仪tcp协议 平台：server  rfid：客户端
 *
 * @author tzz
 */
public class AMETEKSurfaceVisionGateway extends SocketGatewayBase {
    private static Logger logger = LoggerFactory.getLogger(AMETEKSurfaceVisionGateway.class);
    private TcpIoService ioService = null;
    private SessionFactory sessionFactory = null;
    private AtomicBoolean shouldRun = new AtomicBoolean(false);
    private String deviceId;
    private BlockingQueue<SocketReturnMessage> sendQueue = new LinkedBlockingQueue<>(1);

    /**
     * 下发命令超时时间，单位毫秒
     */
    private static int maxSendTime = 5000;

    private static final int sleepInternal = 100;
    //10毫秒

    @SneakyThrows
    @Override
    public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
        logger.info("send msg is :{}", returnMsg);
        //阻塞队列，容量为1，若上一个命令未发送则阻塞
        sendQueue.put(returnMsg);

        ExeResultVo sendResult = new ExeResultVo();
        sendResult.setSuccess(false);

        try {
            SurfaceVisionSocketReturnMessage sendMsg = new SurfaceVisionSocketReturnMessage();
            BeanUtils.copyProperties(returnMsg, sendMsg);
            sendMsg.setSendReturnFlag(false);

            //发送下发命令
            List<IoSession> sessions = sessionFactory.getSessions();
            SurfaceVisionIoSession ioSession = (SurfaceVisionIoSession) sessions.get(0);
            logger.info("send msg SurfaceVisionIoSession is :{}", ioSession);
            ioSession.send(sendMsg);

            //等待下发命令返回，若等待时间超过最大等待时长，直接返回下发失败,每隔sleepInternal时间判断一次
            long sendTime = System.currentTimeMillis();
            while (!sendMsg.getSendReturnFlag()) {
                long now = System.currentTimeMillis();
                if ((now - sendTime) > (maxSendTime)) {
                    sendResult.setMessage("下发命令响应超时,超时时间为：" + maxSendTime + "ms");
                    ioSession.setCurrentSend(null);
                    return sendResult;
                }
                Thread.sleep(sleepInternal);
            }
            ioSession.setCurrentSend(null);
            logger.info("send result is :{}", sendMsg.getRealData());

            sendResult = sendMsg.getRealData();
        }catch (Exception e){
            logger.error("下发中断，异常为: ", e);
            sendResult.setMessage("下发异常中断");
        }finally {
            //空出阻塞队列
            sendQueue.take();
        }
        return sendResult;
    }


    @Override
    public void start() {
        if(state == GatewayState.RUNNING) {
            return;
        }

        //配置信息校验
        ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);

        maxSendTime = socketParam.getTimeout();

        if (StringUtils.isEmpty(socketParam.getListenIp()) || socketParam.getListenPort() == null) {
            throw new BusinessException("未正确配置监听ip地址和监听端口。");
        }

        logger.info("AMETEKSurfaceVision网关:{}读取启动配置参数:{}",instanceVo.getRunId(), getInstanceVo().getParameter());
        //读取网关连接配置参数
        RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
        List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());

        //一个网关连接只能配置一个设备
        if(deviceVos.size() > 1) {
            throw new BusinessException("网关Id:" +instanceVo.getRunId() + "为AMETEKSurfaceVision网关，只允许关联一个设备Id");
        }

        deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;

        if(StringUtils.isEmpty(deviceId)) {
            throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
        }

        //创建session工厂并初始化
        DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
        SessionFactory factory = new SurfaceVisionSessionFactory(deviceId);
        factory.init(serviceProvider, this);

        //初始化channel
        SurfaceVisionChannelInitializer<SurfaceVisionFrameDecoder> channelInitializer =
            new SurfaceVisionChannelInitializer<>(factory);

        //初始化ioService
        defaultIoService.init(instanceVo, factory, channelInitializer);

        ioService = defaultIoService;
        sessionFactory = factory;

        //启动监听
        boolean open = ioService.open();

        if(open == true) {
            state = GatewayState.RUNNING;
            logger.info("AMETEKSurfaceVision网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
            instanceVo.setLogOpen(true);
            //心跳机制
            shouldRun.set(true);
//
//            Integer keepAlive = socketParam.getKeepAlive();
//
//            if(keepAlive == null || keepAlive < 10) {
//                keepAlive = 10;
//            }else if (keepAlive > 60) {
//                keepAlive = 60;
//            }
//
//            SurfaceVisionAliveCheckTask task = new SurfaceVisionAliveCheckTask(keepAlive, shouldRun, factory);
//
//            Thread thread = new Thread(task, "ametek-surface-alive-check-thread-" + getInstanceVo().getRunId());
//            thread.start();
        }else {
            logger.info("AMETEKSurfaceVision网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
        }

    }

    @Override
    public void shutdown() {
        if(state == GatewayState.CLOSED) {
            return;
        }

        //关闭channel
        if(sessionFactory != null) {
            for (IoSession ioSession : sessionFactory.getSessions()) {
                SurfaceVisionIoSession imsIoSession = (SurfaceVisionIoSession)ioSession;
                imsIoSession.close();
            }
        }

        //关闭监听和会话
        boolean close = ioService.close();
        if(close == true) {
            sessionFactory = null;
            state = GatewayState.CLOSED;
            shouldRun.set(false);
            logger.info("AMETEKSurfaceVision网关:{}关闭成功", instanceVo.getRunId());
        }else {
            logger.info("AMETEKSurfaceVision网关:{}关闭失败", instanceVo.getRunId());
        }
    }

    @Override
    public Set<String> getActiveDeviceIds() {
        Set<String> set = Sets.newHashSet();
        set.add(deviceId);
        return set;
    }
}
