package net.northking.cctp.designer.ws.client;


import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import net.northking.cctp.designer.ws.InstructSetMsg;
import net.northking.cctp.designer.ws.RobotEngineConnetStatusBo;
import net.northking.cctp.designer.ws.WsManyWaysBo;
import net.northking.cctp.designer.ws.WsUtils;
import net.northking.cctp.designer.ws.constants.PcuiDesignerConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.*;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@ClientEndpoint
public class EngineWsClient {
    private static final Logger logger = LoggerFactory.getLogger(EngineWsClient.class);

    private String sessionId;

    private Session session;

    private  URI uri;

    private boolean closeFlag = false;

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public String getSessionId() {
        return sessionId;
    }

    public void setSessionId(String sessionId) {
        this.sessionId = sessionId;
    }

    public EngineWsClient(URI uri,String sessionId) {
        this.uri = uri;
        try {
            this.session = ContainerProvider.getWebSocketContainer().connectToServer(this, uri);
            //设置传输数据的大小
            this.session.setMaxTextMessageBufferSize(5 * 1024 *1024);
            this.sessionId = sessionId;
            //发送心跳
            this.sendHeart();
        } catch (Exception e) {
            logger.error("第一次连接引擎ws异常:",e);
            //第一次连接不上直接结束不在重新连接
        }

    }
    private boolean reconnect(){
        //通知前端重新连接机器人中


        WsManyWaysBo wsManyWaysBo = WsUtils.sessionMap.get(this.sessionId);


        if (wsManyWaysBo != null){
            RobotEngineConnetStatusBo statusBo = WsUtils.connectStatus.get(wsManyWaysBo.getSessionId());
            if (null != statusBo){
                //判断执行引擎是否已经发送过重新连接中
                int robotStatus = statusBo.getRobotStatus();
                int engineStatus = statusBo.getEngineStatus();
                statusBo.setEngineStatus(PcuiDesignerConstant.ENG_STA_CONNECTING);//置为连接中
                if (robotStatus == PcuiDesignerConstant.ROB_STA_CONNECTED && engineStatus == PcuiDesignerConstant.ENG_STA_CONNECTED){
                    WsUtils.sendMsgFrontConnetStatus(wsManyWaysBo,InstructSetMsg.connecting,InstructSetMsg.engine);
                }
            }
        }

        //当连接不正常且
        while (!this.isNormal()){
            //当为正常关闭时直接返回false无需重连了.
            if (this.closeFlag){
                return false;
            }
            if (atomicInteger.get() >= 3){
                //如果三次还连接不上将关闭标识置为正常关闭
                this.closeFlag = true;
                //已正常关闭或者重新连接不上需要断开执行机的ws
                WsUtils.closeRobotAndEngineWs(this.sessionId,PcuiDesignerConstant.RP_RETRY_FAILURE);
                //连接失败通知前端
                if (wsManyWaysBo != null){
                    //需要调用资源释放
                    wsManyWaysBo.getFrontDatasWebsocket().release();
                    RobotEngineConnetStatusBo statusBo = WsUtils.connectStatus.get(wsManyWaysBo.getSessionId());
                    if (null != statusBo){
                        //判断执行引擎是否已经发送过重新连接中
                        int robotStatus = statusBo.getRobotStatus();
                        int engineStatus = statusBo.getEngineStatus();
                        statusBo.setEngineStatus(PcuiDesignerConstant.ENG_STA_DISCONNECTED);//置为连接失败
                        if ((engineStatus == PcuiDesignerConstant.ENG_STA_CONNECTING && robotStatus == PcuiDesignerConstant.ROB_STA_CONNECTED) || (engineStatus == PcuiDesignerConstant.ENG_STA_CONNECTING && robotStatus == PcuiDesignerConstant.ROB_STA_CONNECTING)){
                            WsUtils.sendMsgFrontConnetStatus(wsManyWaysBo,InstructSetMsg.disconnect,InstructSetMsg.engine);
                        }
                    }
                }
                return false;
            }
            String oldSessionId = this.session.getId();
            ScheduledFuture<?> scheduledFuture = WsUtils.scheduledFutures.get(oldSessionId);
            try {
                this.session = ContainerProvider.getWebSocketContainer().connectToServer(this, this.uri);
            } catch (Exception e) {
                logger.error("重试连接引擎ws异常:", e);
                //连接失败增加次数增加重连间隔3秒
                atomicInteger.incrementAndGet();
                //每隔三秒
                ThreadUtils.sleep(3000);
                continue;
            }
            //设置传输数据的大小
            this.session.setMaxTextMessageBufferSize(5 * 1024 * 1024);
            if (null != scheduledFuture) {
                //重新连接上后需要重新将心跳线程任务放入map,删除老加入新的
                WsUtils.scheduledFutures.remove(oldSessionId);
                WsUtils.scheduledFutures.put(this.session.getId(), scheduledFuture);
            }
            //连接上了重置计数器
            atomicInteger.set(0);
            //连接成功通知前端
            if (wsManyWaysBo != null) {
                RobotEngineConnetStatusBo statusBo = WsUtils.connectStatus.get(wsManyWaysBo.getSessionId());
                if (null != statusBo) {
                    //判断执行引擎是否已经发送过重新连接中
                    int engineStatus = statusBo.getEngineStatus();
                    statusBo.setEngineStatus(PcuiDesignerConstant.ENG_STA_CONNECTED);//置为连接成功
                    if (statusBo.getRobotStatus() == PcuiDesignerConstant.ROB_STA_CONNECTED && engineStatus == PcuiDesignerConstant.ENG_STA_CONNECTING) {
                        WsUtils.sendMsgFrontConnetStatus(wsManyWaysBo, InstructSetMsg.connected, InstructSetMsg.engine);
                    }
                }
            }
        }
        return true;
    }

    private void sendHeart() {
        ScheduledFuture<?> scheduledFuture = WsUtils.scheduledExecutorService.scheduleAtFixedRate(() -> {
            if (this.isNormal()) {
                //每次发送心跳前检查map中是否还包含该对象
                WsManyWaysBo wsManyWaysBo = WsUtils.sessionMap.get(this.sessionId);
                if (wsManyWaysBo != null) {
                    JSONObject msg = new JSONObject();
                    msg.put(InstructSetMsg.cmd, PcuiDesignerConstant.VALUE_MSG_PING2);
                    msg.put(InstructSetMsg.sessionId, sessionId);
                    //TODO 暂不发送心跳
                } else {
                    WsUtils.closeRobotAndEngineWs(this.sessionId, PcuiDesignerConstant.RP_ENG_DISCONNECTED + this.sessionId);

                    ScheduledFuture<?> scheduledFutureMap = WsUtils.scheduledFutures.get(this.session.getId());
                    if (null != scheduledFutureMap){
                        WsUtils.scheduledFutures.remove(this.session.getId());
                        scheduledFutureMap.cancel(true);
                        logger.info("引擎心跳任务结束:{}",this.sessionId);
                    }
                }
            } else {
                if (this.closeFlag || !this.reconnect()) {
                    //如果是正常关闭或者重连接失败则停止发送心跳

                    ScheduledFuture<?> scheduledFutureMap = WsUtils.scheduledFutures.get(this.session.getId());
                    if (null != scheduledFutureMap){
                        WsUtils.scheduledFutures.remove(this.session.getId());
                        scheduledFutureMap.cancel(true);
                        logger.info("引擎心跳任务结束:{}",this.sessionId);
                    }
                } else if (this.session.isOpen()) {
                    //说明重新连接成功发送心跳
                    JSONObject msg = new JSONObject();
                    msg.put(InstructSetMsg.cmd, PcuiDesignerConstant.VALUE_MSG_PING2);
                    msg.put(InstructSetMsg.sessionId, sessionId);
                }
            }
        }, PcuiDesignerConstant.INITIAL_DELAY, PcuiDesignerConstant.PERIOD, TimeUnit.SECONDS);
        WsUtils.scheduledFutures.put(this.session.getId(),scheduledFuture);
    }

    public void sendMessage(String msg) {
        if (this.session.isOpen()){
            this.session.getAsyncRemote().sendText(msg);
            logger.info("推送给执行引擎的指令:{}", msg);
        }
    }

    @OnMessage
    public void onMessage(String message) {
        if (StringUtils.isNotBlank(message)){
            JSONObject jsonObject = JSONObject.parseObject(message);
            if (!PcuiDesignerConstant.CMD_PONG.equals(jsonObject.getString(InstructSetMsg.cmd))){
                //收到服务端的消息,发送给前端
                logger.info("执行引擎返回的脚本:{}",message);
                //将消息标注为引擎发送的
                jsonObject.put(InstructSetMsg.robot_engine,InstructSetMsg.engine);
                WsUtils.sendMsgFront(this,jsonObject.toJSONString());
            }
        }
    }

    @OnClose
    public void onClose(CloseReason cr) {
        if (null != cr && cr.getReasonPhrase() != null && cr.getReasonPhrase().contains(InstructSetMsg.sit)){
            this.closeFlag = true;
            //说明是正常关闭
            logger.info("引擎通道正常关闭:{},{}",this.sessionId,cr.getReasonPhrase());
            WsUtils.closeRobotAndEngineWs(this.sessionId,PcuiDesignerConstant.RP_NO_AUTO_RECONNECT_CLOSE);
        }else if(!this.closeFlag && (null == cr || cr.getReasonPhrase() == null || !cr.getReasonPhrase().contains(InstructSetMsg.sit))){
            if (null != cr){
                logger.info("引擎通道异常关闭:{},:{}",cr.getCloseCode(),cr.getReasonPhrase());
            }
            this.reconnect();

        }
    }

    @OnError
    public void onError(Throwable xb) {
        logger.error("引擎ws通道异常:",xb);
    }

    public void optClose(String msg){
        if (this.session.isOpen()){
            try {
                this.session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE,msg + InstructSetMsg.sit));
            } catch (IOException e) {
                logger.error("关闭引擎ws异常:",e);
            }
        }
    }
    public boolean isNormal(){
        return this.session != null && this.session.isOpen();
    }
}
