package com.its.dsrc.xnettcp.dsrc.process.response;

import com.beanit.asn1bean.ber.types.BerEnum;
import com.beanit.asn1dsrc.dsrc.*;
import com.beanit.asn1dsrc.enums.eObjectId;
import com.beanit.asn1dsrc.enums.eRejectSubscription;
import com.beanit.asn1dsrc.util.DsrcAsn1Utils;
import com.its.app.utils.NettyUtils;
import com.its.dsrc.config.RunningConfig;
import com.its.dsrc.entity.TbRseCtlr;
import com.its.dsrc.xnettcp.dsrc.process.service.SubscriptionService;
import com.its.dsrc.xnettcp.dsrc.process.service.impl.SubscriptionRegisterService;
import com.its.dsrc.xnettcp.dsrc.process.service.impl.SubscriptionSingleService;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SubscriptionResponse implements DsrcAsn1Response {
    private TbRseCtlr obj;
    private ChannelHandlerContext ctx;
    private C2CAuthenticatedMessage c2c;

    public SubscriptionResponse(TbRseCtlr obj, ChannelHandlerContext ctx, C2CAuthenticatedMessage c2c) {
        this.obj = obj;
        this.ctx = ctx;
        this.c2c = c2c;
    }

    @Override
    public boolean response(RunningConfig runningConfig) {
        String ipAddress = NettyUtils.getRemoteIpAddress(this.ctx.channel());
        log.debug("SubscriptionResponse.response: {}", ipAddress);

        int dataPacketNmbr = this.c2c.getDatexDataPacketNumber().intValue();
        int objectId = 0;
        SubscriptionService subscriptionService = null;
        C2CAuthenticatedMessage resC2c = null;
        PDUs pdus = this.c2c.getPdu();
        Subscription subscription = pdus.getSubscription();
        if (subscription != null) {
            int subscribeSerialNbr = subscription.getDatexSubscribeSerialNbr().intValue();
            SubscriptionType subscriptionType = subscription.getDatexSubscribeType();
            BerEnum cancelReasonCd = subscriptionType.getDatexSubscribeCancelReasonCd();
            if (subscriptionType != null) {
                SubscriptionData subscriptionData = subscriptionType.getSubscription();
                if (subscriptionData != null) {
                    boolean persistentBool = subscriptionData.getDatexSubscribePersistentBool().value;
                    int statusCd           = subscriptionData.getDatexSubscribeStatusCd().value.intValue();   // new, update
                    int publishFormatCd    = subscriptionData.getDatexSubscribePublishFormatCd().value.intValue();
                    int priorityNbr        = subscriptionData.getDatexSubscriptionPriorityNbr().value.intValue();
                    boolean guaranteeBool  = subscriptionData.getDatexSubscribeGuaranteeBool().value;

                    objectId = DsrcAsn1Utils.getObjectId(subscriptionData.getDatexSubscribePdu().getEndApplicationMessageId().value);
                    log.info("SubscriptionResponse.response: objectId: {}", objectId);

                    if (objectId != eObjectId.OBJ_ProbeVehicleDetectionRoadSide.getValue() &&
                        objectId  > eObjectId.OBJ_DSRCRecentOBUTransactionInfo.getValue()) {
                        // Reject
                        resC2c = DsrcAsn1Reject.makeC2CAuthenticatedMessage(this.obj, this.ctx.channel(), this.c2c,
                                eRejectSubscription.Reject_Subscription_cd_invalidSubscriptionMsgId.getValue());
                        log.info("SubscriptionResponse.response: {}, Reject, objectId: {}", ipAddress, objectId);
                    }
                    else {
                        SubscriptionMode subscriptionMode = subscriptionData.getDatexSubscribeMode();
                        if (subscriptionMode != null) {
                            // subscriptionMode = single, event-driven, periodic
                            if (subscriptionMode.getSingle() != null) {
                                log.info("SubscriptionResponse.response: {}, SubscriptionSingleService", ipAddress);
                                subscriptionService = SubscriptionSingleService.getInstance();
                            } else if (subscriptionMode.getEventDriven() != null) {
                                log.info("SubscriptionResponse.response: {}, SubscriptionRegisterService[EventDriven]", ipAddress);
                                subscriptionService = SubscriptionRegisterService.getInstance();
                            } else if (subscriptionMode.getPeriodic() != null) {
                                log.info("SubscriptionResponse.response: {}, SubscriptionRegisterService[Periodic]", ipAddress);
                                subscriptionService = SubscriptionRegisterService.getInstance();
                            }
                            if (guaranteeBool) {
                                resC2c = DsrcAsn1Accept.makeC2CAuthenticatedMessage(this.obj, this.ctx.channel(), this.c2c);
                            }
                        } else {
                            log.info("SubscriptionResponse.response: {}, SubscriptionMode null", ipAddress);
                        }
                    }
                }
            } else if (cancelReasonCd != null) {
                // Cancel
                int cancelReasonId = cancelReasonCd.value.intValue();
                resC2c = DsrcAsn1Accept.makeC2CAuthenticatedMessage(this.obj, this.ctx.channel(), this.c2c);
                log.info("SubscriptionResponse.response: {}, Accept, cancelReasonCd: {}", ipAddress, cancelReasonId);
            }
        }

        if (subscriptionService != null) {
            subscriptionService.response(this.obj, this.ctx.channel(), objectId, subscription);
        }

        if (resC2c != null) {
            // send accept or reject
            ChannelFuture f = this.ctx.channel().writeAndFlush(resC2c);
            f.awaitUninterruptibly();
            if (!f.isDone() && !f.isSuccess()) {
                log.error("SubscriptionResponse.response: {}. packet send Failed.", ipAddress);
            }
        }
        return true;
    }

}
