package com.cm.central.control.client.socket.handler;

import com.alibaba.fastjson.JSONObject;
import com.cm.central.control.client.socket.config.properties.SocketClientProperties;
import com.cm.central.control.client.socket.manager.SocketClientManager;
import com.cm.central.control.client.socket.socket.SocketClientRunnable;
import com.cm.socket.enums.SocketCodeEnum;
import com.cm.socket.enums.SocketTypeMessageEnum;
import com.cm.socket.pojo.Message;
import com.cm.socket.pojo.SocketResult;
import com.cm.socket.service.ISocketService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: MessageClientHandler
 * @Description: 消息客户端处理器
 * @Author: WangGeng
 * @Date: 2020/7/6 9:34 上午
 * @Version: 1.0
 **/
public class SocketClientHandler extends SimpleChannelInboundHandler<Message> {

    private static final Logger LOG = LoggerFactory.getLogger(SocketClientHandler.class);
    private SocketClientRunnable socketClientRunnable;
    private SocketClientProperties socketClientProperties;
    private ISocketService pingServiceImpl;
    private ISocketService clientInfoServiceImpl;
    private ISocketService exceptionServiceImpl;
    private ISocketService loginServiceImpl;
    private ISocketService errorServiceImpl;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        LOG.debug("与服务器建立Socket链接已经建立，登录");
        loginServiceImpl.autoReply(ctx);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Message message) throws Exception {
        if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_PONG.getType()) {
            pingServiceImpl.readMessage(channelHandlerContext, message);
        } else if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_CLIENT_LOGIN.getType()) {
            loginServiceImpl.readMessage(channelHandlerContext, message);
        } else if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_EXCEPTION.getType()) {
            exceptionServiceImpl.readMessage(channelHandlerContext, message);
        } else if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_ERROR.getType()) {
            errorServiceImpl.readMessage(channelHandlerContext, message);
        } else {
            SocketResult<String> socketResult = new SocketResult<>();
            socketResult.setCode(SocketCodeEnum.ERROR.getCode());
            socketResult.setErrorMsg("消息类型暂不支持");
            Message resultMessage = new Message();
            resultMessage.setStart(SocketTypeMessageEnum.MESSAGE_TYPE_START.getType());
            resultMessage.setType(SocketTypeMessageEnum.MESSAGE_TYPE_ERROR.getType());
            resultMessage.setContent(JSONObject.toJSONString(socketResult));
            channelHandlerContext.channel().writeAndFlush(message);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        LOG.error("与服务断开连接");
        SocketClientManager socketClientManager = SocketClientManager.getInstance();
        int currentReconnectCount = socketClientManager.getCurrentReconnectCount();
        int waitTime = socketClientManager.getCurrentReconnectTime();
        if (socketClientManager.getCurrentReconnectCount() > socketClientProperties.getMaxReconnectCount()) {
            LOG.error("服务器重连失败");
            throw new RuntimeException("服务器重连失败");
        }
        LOG.error(waitTime + "s后进行第" + currentReconnectCount + "次重连");
        ctx.channel().eventLoop().schedule(() -> {
            LOG.debug("重新登录...");
            socketClientRunnable.run();
        }, waitTime, TimeUnit.SECONDS);
        socketClientManager.setCurrentReconnectCount(++currentReconnectCount);
        if (socketClientProperties.getReconnectTimeStep() > 0) {
            socketClientManager.setCurrentReconnectTime(waitTime + socketClientProperties.getReconnectTimeStep());
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LOG.error(cause.getMessage(), cause);
        ctx.close();
    }

    public void setSocketClientRunnable(SocketClientRunnable socketClientRunnable) {
        this.socketClientRunnable = socketClientRunnable;
    }

    public void setSocketClientProperties(SocketClientProperties socketClientProperties) {
        this.socketClientProperties = socketClientProperties;
    }

    public void setPingServiceImpl(ISocketService pingServiceImpl) {
        this.pingServiceImpl = pingServiceImpl;
    }

    public void setClientInfoServiceImpl(ISocketService clientInfoServiceImpl) {
        this.clientInfoServiceImpl = clientInfoServiceImpl;
    }

    public void setExceptionServiceImpl(ISocketService exceptionServiceImpl) {
        this.exceptionServiceImpl = exceptionServiceImpl;
    }

    public void setLoginServiceImpl(ISocketService loginServiceImpl) {
        this.loginServiceImpl = loginServiceImpl;
    }

    public void setErrorServiceImpl(ISocketService errorServiceImpl) {
        this.errorServiceImpl = errorServiceImpl;
    }
}
