package com.its.dsrc.xnettcp.dsrc.handler;

import com.beanit.asn1dsrc.dsrc.C2CAuthenticatedMessage;
import com.beanit.asn1dsrc.enums.eAuthInfo;
import com.its.app.utils.NettyUtils;
import com.its.dsrc.config.RunningConfig;
import com.its.dsrc.entity.TbRseCtlr;
import com.its.dsrc.global.AppRepository;
import com.its.dsrc.process.DbmsDataProcess;
import com.its.dsrc.xnettcp.dsrc.process.response.InitiateResponse;
import com.its.dsrc.xnettcp.dsrc.process.response.LoginResponse;
import com.its.dsrc.xnettcp.dsrc.process.service.LoginDeviceService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
//@Component
//@ChannelHandler.Sharable
public class DsrcAsn1ServerLoginInboundHandler extends ChannelInboundHandlerAdapter {

    private final RunningConfig config;
    private final DsrcAsn1ServerPacketInboundHandler dsrcAsn1ServerPacketInboundHandler;
    private final DbmsDataProcess dbmsDataProcess;
    private final RunningConfig runningConfig;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
    }

    /*
     * 통신 연결 후 최초 로그인 패킷 처리를 위한 핸들러
     */
    public void channelRead(ChannelHandlerContext ctx, Object msg) {

        //String tcpAddress = NettyUtils.getTcpAddress(ctx.channel());    // local/remote address 를 폼함한 문자열
        String ipAddress = NettyUtils.getRemoteIpAddress(ctx.channel());
        TbRseCtlr obj = AppRepository.getInstance().getCtlrIpMap().get(ipAddress);
        if (null == obj) {
            log.error("DsrcAsn1ServerLoginInboundHandler.-----------channelRead: {}. Unknown controller. will be closed.", ipAddress);
            DsrcAsn1ServerIdleStateConnectionHandler.disconnectChannel(ctx.channel());
            return;
        }

        MDC.put("id", obj.getLogKey());

        log.info("DsrcAsn1ServerLoginInboundHandler.-----------channelRead: {}", ipAddress);

        if (!(msg instanceof C2CAuthenticatedMessage)) {
            log.error("DsrcAsn1ServerLoginInboundHandler.-----------channelRead: {}. Unknown message. will be closed.", ipAddress);
            DsrcAsn1ServerIdleStateConnectionHandler.disconnectChannel(ctx.channel());
            return;
        }

        int allIdleTimeSec = 300;
        C2CAuthenticatedMessage c2c = (C2CAuthenticatedMessage)msg;
        eAuthInfo cmd = eAuthInfo.getByValue(c2c.getDatexAuthenticationInfoText().value[0]);
        if (cmd == eAuthInfo.AI_Initiate) {
            InitiateResponse response = new InitiateResponse(obj, ctx, c2c);
            if (!response.response(this.runningConfig)) {
                log.error("DsrcAsn1ServerLoginInboundHandler.-----------channelRead: {}. AI_Initiate failed. will be closed.", ipAddress);
                DsrcAsn1ServerIdleStateConnectionHandler.disconnectChannel(ctx.channel());
                return;
            }
            LoginDeviceService.getInstance().requestLogin(obj, ctx.channel(), this.runningConfig);
        } else if (cmd == eAuthInfo.AI_Login)  {
            LoginResponse response = new LoginResponse(obj, ctx, c2c);
            if (!response.response(this.runningConfig)) {
                log.error("DsrcAsn1ServerLoginInboundHandler.-----------channelRead: {}. AI_Login failed. will be closed.", ipAddress);
                DsrcAsn1ServerIdleStateConnectionHandler.disconnectChannel(ctx.channel());
                return;
            }
            return;
        } else {
            log.warn("DsrcAsn1ServerLoginInboundHandler: {}", cmd);
        }

        // 로그인이 성공하면
        // 통신 IDLE 시 네트워크 체크 확인 패킷전송을 위한 핸들러를 추가한다.
        // 패킷 처리 용 핸들러를 추가한다.
        // 로그인 이전 네트워크 IDLE 체크 핸들러 삭제
        // 로그인 처리 핸들러 삭제
        // 로그인 패킷 처리 핸들러 삭제
        //int allIdleTimeSec = obj.getLogin().getDatexLoginHeartbeatDurationMaxQty().value.intValue()+5;
        log.info("DsrcAsn1ServerLoginInboundHandler.-----------channelRead: {}, allIdleTimeSec: {} sec.", ipAddress, allIdleTimeSec);
        DsrcAsn1ServerIdleStatePacketHandler dsrcAsn1ServerIdleStatePacketHandler = new DsrcAsn1ServerIdleStatePacketHandler(
                0,
                0,
                allIdleTimeSec,
                TimeUnit.SECONDS
        );
        ctx.channel().pipeline().addAfter("dsrcAsn1ServerConnectionIdleStateHandler","dsrcAsn1ServerIdleStateHandler", dsrcAsn1ServerIdleStatePacketHandler);    // packet idle handler add
        ctx.channel().pipeline().addAfter("dsrcAsn1ServerLoginInboundHandler","dsrcAsn1ServerPacketInboundHandler", this.dsrcAsn1ServerPacketInboundHandler); // packet distribute handler add
        ctx.channel().pipeline().remove("dsrcAsn1ServerConnectionIdleStateHandler");      // login idle handler remove
        ctx.channel().pipeline().remove("dsrcAsn1ServerConnectionHandler");     // connection handler remove
        ctx.channel().pipeline().remove(this);                     // login handler remove

        MDC.remove(obj.getLogKey());
        MDC.clear();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        log.warn("DsrcAsn1ServerLoginInboundHandler.---channelReadComplete");
        super.channelReadComplete(ctx);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        log.warn("DsrcAsn1ServerLoginInboundHandler.-----channelRegistered");
        super.channelRegistered(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        log.warn("DsrcAsn1ServerLoginInboundHandler.---channelUnregistered");
        super.channelUnregistered(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("DsrcAsn1ServerLoginInboundHandler.-------exceptionCaught: {}", cause.toString());
        DsrcAsn1ServerIdleStatePacketHandler.disconnectChannel(null, ctx.channel());
        super.exceptionCaught(ctx, cause);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        log.warn("DsrcAsn1ServerLoginInboundHandler.----userEventTriggered");
        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //log.warn("DsrcAsn1ServerLoginInboundHandler.----------handlerAdded");
        super.handlerAdded(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        //log.warn("DsrcAsn1ServerLoginInboundHandler.--------handlerRemoved");
        super.handlerRemoved(ctx);
    }
}
