package com.tsi.comm.server.tcp.initializer;

import com.tsi.comm.server.repository.TsiAlarmManager;
import com.tsi.comm.server.vo.TsiAlarmConfigVo;
import com.tsi.comm.server.xnet.NettyUtils;
import com.tsi.comm.server.config.TsiCvimServerConfig;
import com.tsi.comm.server.tcp.codec.CvimServerByteBufMessageDecoder;
import com.tsi.comm.server.tcp.codec.CvimServerEncoder;
import com.tsi.comm.server.tcp.handler.CvimServerInboundMessageHandler;
import com.tsi.common.spring.SpringUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;

public class CvimServerInitializer extends ChannelInitializer<Channel> {

    private final TsiCvimServerConfig config;
    private final CvimServerByteBufMessageDecoder cvimServerByteBufMessageDecoder;
    private final CvimServerInboundMessageHandler cvimServerInboundMessageHandler;
    private final CvimServerEncoder cvimServerEncoder;
    private int readerIdleTimeSeconds;

    public CvimServerInitializer(TsiCvimServerConfig config) {
        this.config = config;
        this.cvimServerByteBufMessageDecoder = SpringUtils.getBean(CvimServerByteBufMessageDecoder.class);
        this.cvimServerInboundMessageHandler = SpringUtils.getBean(CvimServerInboundMessageHandler.class);
        this.cvimServerEncoder = SpringUtils.getBean(CvimServerEncoder.class);
        TsiAlarmManager alarmManager = SpringUtils.getBean(TsiAlarmManager.class);
        this.readerIdleTimeSeconds = config.getReaderIdleTimeSeconds();
        TsiAlarmConfigVo vo = alarmManager.get(TsiAlarmConfigVo.COMM_02);
        if (vo != null) {
            this.readerIdleTimeSeconds = vo.getValue();
        }
        if (this.readerIdleTimeSeconds < 5) {
            this.readerIdleTimeSeconds = 5;
        }
    }

    @Override
    protected void initChannel(Channel channel) throws Exception {
        final String remoteIpAddress = NettyUtils.getRemoteIpAddress(channel);
        if (this.config.isInWhitelistIps(remoteIpAddress)) {
            // FOR L4, whitelist ips
//            channel.disconnect();
            channel.close();
            return;
        }

        // 교차로 제어기는 통신 연결시 IP로 체크하지 않고 처음 데이터를 수신했을 경우에 노드 ID를 확인 할 수 있다.
        // 공단에서 교차로 제어기의 IP 주소를 관리하지 않는다.
        IdleStateHandler idleStateHandler = new IdleStateHandler(this.readerIdleTimeSeconds, 0, 0);
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast("idleStateHandler", idleStateHandler);
        pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(2048, 2, 2, -2, 0));
        pipeline.addLast("packetDecoder", this.cvimServerByteBufMessageDecoder);
        pipeline.addLast("packetInboundHandler", this.cvimServerInboundMessageHandler);
        pipeline.addLast("frameEncoder", this.cvimServerEncoder);
    }
}
