package com.its.pis.xnettcp.vds.handler;

import com.its.app.utils.NettyUtils;
import com.its.pis.entity.TbVdsCtlr;
import com.its.pis.global.AppRepository;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.util.concurrent.TimeUnit;

@Slf4j
@ChannelHandler.Sharable
public class VdsTcpClientIdleHandler extends IdleStateHandler {

    public VdsTcpClientIdleHandler(long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit) {
        super(readerIdleTime, writerIdleTime, allIdleTime, unit);
    }

    @Override
    protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) {
        String ID = "???";
        String ipAddress = NettyUtils.getRemoteIpAddress(ctx.channel());
        TbVdsCtlr obj = AppRepository.getInstance().getCtlrIpMap().get(ipAddress);
        if (obj != null) {
            MDC.put("id", obj.getLogKey());
            ID = obj.getVDS_CTLR_ID();
        }
        if (evt.state() == IdleState.ALL_IDLE) {
            log.error("[{}]. IDLE: VdsTcpClientIdleHandler.------channelIdle: ALL_IDLE", ID);
            VdsTcpClientIdleHandler.disconnectChannel(ctx.channel());
        }
        else if (evt.state() == IdleState.READER_IDLE) {
            log.warn("[{}]. IDLE: VdsTcpClientIdleHandler.------channelIdle: READER_IDLE", ID);
            VdsTcpClientIdleHandler.disconnectChannel(ctx.channel());
        }
        else if (evt.state() == IdleState.WRITER_IDLE) {
            log.warn("[{}]. IDLE: VdsTcpClientIdleHandler.------channelIdle: WRITER_IDLE", ID);
        }

        if (obj != null) {
            MDC.remove(obj.getLogKey());
            MDC.clear();
        }
    }

    /*
     *  클라이언트와의 연결 종료를 위해 호출하는 함수
     */
    public static void disconnectChannel(Channel channel) {
        // 로그인 하지 않은 또는 비정상 접속 네트워크 세션 종료(로그인 처리를 수행하지 않은 세션에 대한 종료)
        String ID = "???";
        String ipAddress = NettyUtils.getRemoteIpAddress(channel);
        TbVdsCtlr obj = AppRepository.getInstance().getCtlrIpMap().get(ipAddress);
        if (obj != null) {
            MDC.put("id", obj.getLogKey());
            ID = obj.getVDS_CTLR_ID();
        }

        log.error("[{}]. DISC: VdsTcpClientIdleHandler.disconnectChannel", ID);
        if (!channel.isActive()) {
            log.error("[{}]. DISC: VdsTcpClientIdleHandler.disconnectChannel: channel already closed.", ID);
        }

        //////////////////////////////////
        // 클라이언트와의 연결을 종료한다.
        //////////////////////////////////
        channel.flush();
        ChannelFuture f = channel.disconnect().awaitUninterruptibly();
        if (!f.isDone() || !f.isSuccess()) {
            log.error("[{}]. DISC: VdsTcpClientIdleHandler.disconnectChannel: isDone {}, isSuccess {}", ID, f.isDone(), f.isSuccess());
        }

        if (obj != null) {
            MDC.remove(obj.getLogKey());
            MDC.clear();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        String ID = "???";
        String ipAddress = NettyUtils.getRemoteIpAddress(ctx.channel());
        TbVdsCtlr obj = AppRepository.getInstance().getCtlrIpMap().get(ipAddress);
        if (obj != null) {
            MDC.put("id", obj.getLogKey());
            ID = obj.getVDS_CTLR_ID();
        }
        log.error("[{}]. EXCE: exceptionCaught: {}", ID, cause.getMessage());
        if (obj != null) {
            MDC.remove(obj.getLogKey());
            MDC.clear();
        }

        ctx.channel().close();
    }
}
