package com.docus.server.common.netty.client.handler;

import com.docus.core.util.DateUtil;
import com.docus.server.common.CommMsg;
import com.docus.server.common.MsgConstants;
import com.docus.server.common.netty.client.NettyClient;
import com.docus.server.common.netty.client.NettyClientProperties;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 处理发送心跳逻辑
 */
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
public class HeartbeatHandler extends ChannelInboundHandlerAdapter {

    private NettyClient nettyClient;

    private NettyClientProperties nettyProperties;

    private String appName;


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("通道激活......");

        CommMsg onlineRegister = CommMsg.builder()
            .messageType(MsgConstants.ONLINE_REGISTER)
            .messageTime(DateUtil.formatDateTime(new Date()))
            .content(appName + " 我来了")
            .build();

        ctx.writeAndFlush(onlineRegister);
        super.channelActive(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if (idleStateEvent.state() == IdleState.WRITER_IDLE) {
                // 一定时间内，通道内未传递消息，发送心跳，保证存活
                log.info("【终端客户端心跳】 after {} seconds no message wrote", nettyProperties.getWriterIdleTimeSeconds());

                CommMsg heartbeat = CommMsg.builder()
                    .messageType(MsgConstants.HEARTBEAT_REQUEST)
                    .messageTime(DateUtil.formatDateTime(new Date()))
                    .build();

                //发送心跳消息，并在发送失败时关闭该接连
                ctx.writeAndFlush(heartbeat).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //如果运行过程中服务端挂了,执行重连机制
        log.info("通道释放==================");
        EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(() -> nettyClient.start(), nettyProperties.getReconnectSeconds(), TimeUnit.SECONDS);
        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        log.error("捕获的异常：{}", cause.getMessage());
        ctx.close();
    }

}
