package com.tsi.sig.server.dto;

import com.tsi.sig.server.vo.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Data
@AllArgsConstructor
@Slf4j
public class EvpsData {
    private EvpsEventDto evpsEvent;
    private EvpsNodeDto evpsNode;
    private EvpsServiceDto evpsService;
    private EvpsSignalDto evpsSignal;
    private EvpServiceVo evpServiceVo;
    private Map<String, PhaseInfo> evpPhaseMap;
    private Map<Integer, RouteInfo> evpRouteMap;
    private Map<Integer, EvpSignalVo> signalMap;

    public EvpsData() {
        this.evpServiceVo = new EvpServiceVo();
        this.evpServiceVo.setPhaseList(new ArrayList<>());
        this.evpServiceVo.setEventList(new ArrayList<>());
        this.evpServiceVo.setNodeList(new ArrayList<>());
        this.evpServiceVo.setRouteList(new ArrayList<>());

        this.evpPhaseMap = new HashMap<>();
        this.evpRouteMap = new HashMap<>();
        this.signalMap = new HashMap<>();
    }

    public void setServiceVo() {

        if (this.evpsService != null) {
            this.evpServiceVo.setServiceId(this.evpsService.getServiceId());
            this.evpServiceVo.setClctDt(this.evpsService.getClctDt().substring(0, 19));
            this.evpServiceVo.setServiceNm(this.evpsService.getServiceNm());
            this.evpServiceVo.setEvNo(this.evpsService.getEvNo());
            this.evpServiceVo.setCurLat(this.evpsService.getCurLat());
            this.evpServiceVo.setCurLng(this.evpsService.getCurLng());
            this.evpServiceVo.setArrLat(this.evpsService.getArrLat());
            this.evpServiceVo.setArrLng(this.evpsService.getArrLng());
            this.evpServiceVo.setArrTm(this.evpsService.getArrTm());
            this.evpServiceVo.setVehLen(this.evpsService.getVehLen());
            this.evpServiceVo.setOcrNo(this.evpsService.getOcrNo());
            this.evpServiceVo.setOcrType(this.evpsService.getOcrType());
            this.evpServiceVo.setServiceDist(this.evpsService.getServiceDist());
            this.evpServiceVo.setStatusCd(this.evpsService.getStatusCd());

            if (this.evpServiceVo.getRouteList() != null && this.evpsService.getRouteList().size() > 0) {
                List<RouteInfo> routeInfos = this.evpsService.getRouteList();
                String serviceId = this.evpsService.getServiceId();
                for (RouteInfo routeInfo : routeInfos) {
                    EvpRouteVo routeVo = new EvpRouteVo();
                    Integer seqNo = routeInfo.getSeqNo();
                    double lat = routeInfo.getLat();
                    double lng = routeInfo.getLng();
                    routeVo.setServiceId(serviceId);
                    routeVo.setLat(lat);
                    routeVo.setLng(lng);
                    routeVo.setSeqNo(seqNo);
                    evpServiceVo.getRouteList().add(routeVo);
                    this.evpRouteMap.put(seqNo, routeInfo);
                }
            }
        }
    }

    public void setNodeList() {
        if (this.evpsNode == null || this.evpsNode.getNodeList().size() == 0) {
            return;
        }

        List<NodeInfo> nodeInfos = this.evpsNode.getNodeList();
        List<EvpNodeVo> nodeList = new ArrayList<>();
        for (NodeInfo nodeInfo : nodeInfos) {
            EvpNodeVo nodeVo = new EvpNodeVo();
            String serviceId = this.evpsNode.getServiceId();
            nodeVo.setServiceId(serviceId);
            Integer seqNo = nodeInfo.getSeqNo();
            Long nodeId = nodeInfo.getNodeId();
            String nodeNm = nodeInfo.getNodeNm();
            double lat = nodeInfo.getLat();
            double lng = nodeInfo.getLng();
            nodeVo.setNodeId(nodeId);
            nodeVo.setNodeNm(nodeNm);
            nodeVo.setLat(lat);
            nodeVo.setLng(lng);
            nodeVo.setSeqNo(seqNo);
            nodeList.add(nodeVo);
            if (nodeInfo.getPhaseList().size() > 0) {
                List<PhaseInfo> phaseList = nodeInfo.getPhaseList();

                for (PhaseInfo phase : phaseList) {
                    String key = seqNo + "_" + nodeId + "_" + phase.getRing() + "_" + phase.getPlanClass() + "_" + phase.getPhaseNo();
                    this.evpPhaseMap.put(key, phase);
                }
            }
        }
        this.evpServiceVo.setNodeList(nodeList);
    }

    public void setEventList() {
        if (this.evpServiceVo.getEventList().size() > 0) {
            this.evpServiceVo.getEventList().clear();
        }

        if (this.evpsEvent != null) {
            EvpEventVo vo = new EvpEventVo();
            EvpsEventDto event = this.evpsEvent;
            vo.setClctDt(event.getClctDt().substring(0, 19));
            vo.setCurLat(event.getCurLat());
            vo.setCurLng(event.getCurLng());
            vo.setEvNo(event.getEvNo());
            vo.setServiceId(event.getServiceId());
            vo.setCurSpd(event.getCurSpd());
            vo.setEventCd(event.getEventCd());
            vo.setRemDist(event.getRemDist());
            this.evpServiceVo.getEventList().add(vo);
        }
    }

    public void setSignalList() {
        if (this.evpsSignal == null || this.evpsSignal.getSignalList().size() == 0) {
            return;
        }

        String serviceId = this.evpsSignal.getServiceId();
        String clctDt =  this.evpsSignal.getClctDt().substring(0, 19);
        List<SignalInfo> signalInfos = this.evpsSignal.getSignalList();
        List<EvpSignalVo> phaseList = new ArrayList<>();
        Map<Integer, SignalInfo> signalInfoMap = new HashMap<>();

        for (SignalInfo info : signalInfos) {
            signalInfoMap.put(info.getSeqNo(), info);
        }

        if (this.signalMap.size() > 0) {
            if (signalInfos.size() != this.evpRouteMap.size()) {
                for (Integer seq : new ArrayList<>(this.evpRouteMap.keySet())) {
                    if (signalInfoMap.get(seq) != null || this.signalMap.get(seq) == null) {
                        continue;
                    }
                    phaseList.add(this.signalMap.get(seq));
                }
            }
        }

        for (SignalInfo signalInfo : signalInfos) {
            EvpSignalVo vo = new EvpSignalVo();
            vo.setServiceId(serviceId);
            vo.setClctDt(clctDt);
            vo.setSeqNo(signalInfo.getSeqNo());
            vo.setNodeId(signalInfo.getNodeId());
            vo.setRemDist(signalInfo.getRemDist());
            vo.setState(signalInfo.getState());
            vo.setPlanClass(signalInfo.getPlanClass());
            vo.setARingPhase(signalInfo.getARingPhase());
            vo.setBRingPhase(signalInfo.getBRingPhase());
            vo.setHoldPhase(signalInfo.getHoldPhase());

            if (this.evpRouteMap.get(signalInfo.getSeqNo()) != null){
                vo.setLat(this.evpRouteMap.get(signalInfo.getSeqNo()).getLat());
                vo.setLng(this.evpRouteMap.get(signalInfo.getSeqNo()).getLng());
            }

            Integer aRing = signalInfo.getARingPhase();
            Integer bRing = signalInfo.getBRingPhase();

            if (signalInfo.getState() == 5) {
                aRing = signalInfo.getHoldPhase();
                bRing = signalInfo.getHoldPhase();
            }

            String aKey = signalInfo.getSeqNo() + "_" + signalInfo.getNodeId() + "_1_" + signalInfo.getPlanClass() + "_" + aRing;
            String bKey = signalInfo.getSeqNo() + "_" + signalInfo.getNodeId() + "_2_" + signalInfo.getPlanClass() + "_" + bRing;

            if (this.evpPhaseMap.get(aKey) != null) {
                PhaseInfo aPhaseInfo = this.evpPhaseMap.get(aKey);
                vo.setAFlowNo(aPhaseInfo.getFlowNo());
                vo.setAHeadAngle(aPhaseInfo.getHeadAngle());
                vo.setAEndAngle(aPhaseInfo.getEndAngle());
                vo.setAHeadLat(aPhaseInfo.getHeadLat());
                vo.setAHeadLng(aPhaseInfo.getHeadLng());
                vo.setAMidLat(aPhaseInfo.getMidLat());
                vo.setAMidLng(aPhaseInfo.getMidLng());
                vo.setAEndLat(aPhaseInfo.getEndLat());
                vo.setAEndLng(aPhaseInfo.getEndLng());
            }
            else {
                log.error("Not Found A Ring Signal Phase Info - SeqNo : {}, NodeId : {}, ringNo : 1, PlanClass : {}, ringPhase : {}", signalInfo.getSeqNo(), signalInfo.getNodeId(), signalInfo.getPlanClass(), aRing);
            }

            if (this.evpPhaseMap.get(bKey) != null) {
                PhaseInfo bPhaseInfo = this.evpPhaseMap.get(bKey);
                vo.setBFlowNo(bPhaseInfo.getFlowNo());
                vo.setBHeadAngle(bPhaseInfo.getHeadAngle());
                vo.setBEndAngle(bPhaseInfo.getEndAngle());
                vo.setBHeadLat(bPhaseInfo.getHeadLat());
                vo.setBHeadLng(bPhaseInfo.getHeadLng());
                vo.setBMidLat(bPhaseInfo.getMidLat());
                vo.setBMidLng(bPhaseInfo.getMidLng());
                vo.setBEndLat(bPhaseInfo.getEndLat());
                vo.setBEndLng(bPhaseInfo.getEndLng());
            }
            else {
                log.error("Not Found B Ring Signal Phase Info - SeqNo : {}, NodeId : {}, ringNo : 2, PlanClass : {}, ringPhase : {}", signalInfo.getSeqNo(), signalInfo.getNodeId(), signalInfo.getPlanClass(), bRing);
            }
            this.signalMap.put(vo.getSeqNo(), vo);
            phaseList.add(vo);
        }
        phaseList.sort(Comparator.comparing(EvpSignalVo::getSeqNo));

        this.evpServiceVo.setPhaseList(phaseList);
    }
}
