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

import com.beanit.asn1dsrc.dsrc.*;
import com.beanit.asn1dsrc.enums.eControlDevice;
import com.beanit.asn1dsrc.enums.eObjectId;
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.ControlDeviceService;
import com.its.dsrc.xnettcp.dsrc.process.service.OBUGatherInfoService;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;

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

    public PublicationResponse(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(ctx.channel());
        log.debug("PublicationResponse.response: {}", ipAddress);

        PDUs pdus = this.c2c.getPdu();
        Publication publication = pdus.getPublication();
        if (publication == null) {
           log.error("PublicationResponse.response: {}, Publication data null", ipAddress);
           return false;
        }

        boolean guaranteed = publication.getDatexPublishGuaranteedBool().value;
        PublishFormat publishFormat = publication.getDatexPublishFormat();
        if (publishFormat.getDatexPublishData() != null) {
            List<PublicationData> list = publishFormat.getDatexPublishData().getPublicationData();
            //log.info("PublicationResponse.response: {}. Publication PublishData. size: {} EA", ipAddress, list.size());
            for (PublicationData data : list) {
                if (data.getDatexPublishType().getDatexPublishData() != null) {
                    try {
                        responsePublicationData(data.getDatexPublishType().getDatexPublishData());
                    } catch (IOException e) {
                        log.error("PublicationResponse.response: Exception: {}", e.toString());
                    }
                }
            }
        }
        else if (publishFormat.getDatexPublishFileNameTxt() != null) {
            log.warn("PublicationResponse.response: {}. Publication PublishFileName.", ipAddress);
        }

        if (guaranteed) {
            //log.info("PublicationResponse.response: {}. guaranteed: true", ipAddress);
            C2CAuthenticatedMessage resC2c = DsrcAsn1Accept.makeC2CAuthenticatedMessage(this.obj, this.ctx.channel(), this.c2c);
            if (resC2c != null) {
                ChannelFuture f = this.ctx.channel().writeAndFlush(resC2c);
                f.awaitUninterruptibly();
                if (!f.isDone() || !f.isSuccess()) {
                    log.info("PublicationResponse.response: {}. guaranteed: response send failed.", ipAddress);
                }
            }
        }
        return true;
    }

    private void responsePublicationData(EndApplicationMessage msg) throws IOException {
        int objectId = DsrcAsn1Utils.getObjectId(msg.getEndApplicationMessageId().value);
        if (objectId == eObjectId.OBJ_ControlDevice.getValue()) {
            // RSE Status
            ByteArrayInputStream berInputStream = new ByteArrayInputStream(msg.getEndApplicationMessageMsg().value);
            ControlDeviceList devices = new ControlDeviceList();
            devices.decode(berInputStream);
            List<ControlDevice> list = devices.getControlDevice();
            log.info("PublicationResponse.responsePublicationData: DSRC Status, objectId: {}, {} EA.", objectId, list.size());
            for (ControlDevice controlDevice : list) {
                if (controlDevice.getVpbdControlDeviceData() != null) {
                    eControlDevice e = eControlDevice.getByValue(controlDevice.getVpbdControlID().value[0]);
                    if (e == eControlDevice.Control_StatusRequest) {
                        //TODO: DSRC Device Status
                        //ControlDeviceService.getInstance().decoding_ControlDevice_Status_AirPoint(this.obj, controlDevice);
                        ControlDeviceService.getInstance().decoding_ControlDevice_Status_ITTelecom(this.obj, controlDevice);
                    }
                    else {
                        log.error("PublicationResponse.responsePublicationData: Unknown: {}", e.toString());
                    }
                }
                else {
                    log.error("PublicationResponse.responsePublicationData: VpbdControlDeviceData Data Null");
                }
            }
        }
        else if (objectId == eObjectId.OBJ_OBUGatherInfo.getValue()) {
            // OBE Traffic
            //log.info("PublicationResponse.responsePublicationData: DSRC OBU Traffic");
            ByteArrayInputStream berInputStream = new ByteArrayInputStream(msg.getEndApplicationMessageMsg().value);
            OBUGatherInfoList obuInfos = new OBUGatherInfoList();
            obuInfos.decode(berInputStream);
            List<OBUGatherInfo> list = obuInfos.getOBUGatherInfo();
            //TODO: OBU Gather Info
            log.info("PublicationResponse.responsePublicationData: {}, DSRC OBU Traffic, OBU: {} EA", this.obj.getMcuID(), list.size());
            OBUGatherInfoService.getInstance().decoding_OBUGatherInfo(this.obj, list);
        }
        else {
            log.error("responsePublicationData.responsePublicationData: Unknown ObjectId: {}", objectId);
        }
    }
}
