package com.utic.center.utic.traf.server.dto;

import com.utic.center.utic.traf.server.dto.utic.TrafficGrade;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.ArrayList;

@Data
@Builder
@NoArgsConstructor//(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class LinkDto  implements Serializable {
    private static final long serialVersionUID = 1L;

    private String linkId;
    private Integer roadUse;
    private Integer roadRank;
    private Integer linkLevel;
    private Integer length;
    private Integer lanes;
    private Integer maxSpeed;
    private Integer minSpeed;

    private String upLinkId;
    private String dnLinkId;
    private String link4Id;
    private ArrayList<String> linkIds;

    private boolean prcsPtrnMissing;    // 패턴 결측 처리 여부(링크 레벨1 인 경우)

    private LinkTrafVal trafFsn;        // 퓨전 소통정보
    private LinkTrafPtrn trafPtrn;      // 현재 주기 패턴값
    private LinkTrafMiss missPsd;       // PSD 알고리즘 수행 값
    private LinkTrafCenterDto trafCenter; // 소통정보 센터 전송 DTO

    public void init() {
        this.upLinkId = "";
        this.dnLinkId = "";
        this.link4Id = "";
        this.linkIds = new ArrayList<>();
        this.prcsPtrnMissing = false;

        this.trafPtrn = new LinkTrafPtrn();
        this.trafFsn = new LinkTrafVal();
        this.missPsd = new LinkTrafMiss();
        this.trafCenter = new LinkTrafCenterDto(this.linkId, this.linkLevel);
    }

    public void initTraf() {
        this.trafFsn.init();
        this.missPsd.init();
        this.trafCenter.init();
    }
    public void initPtrn() {
        this.trafPtrn.init();
    }

    public void makeTrafficCenterDto(String regDate) {
        LinkTrafVal fsn = this.trafFsn;
        this.trafCenter.setTrafValid(fsn.getState().isState());
        this.trafCenter.setRegDate(regDate);
        this.trafCenter.setLinkId(linkId);
        this.trafCenter.setMissValueYn(fsn.getState().getMissValueYn());
        this.trafCenter.setSpeed(fsn.getSpeed());
        this.trafCenter.setTravelTime(fsn.getTravelTime());
        this.trafCenter.setTrafficGrade("0" + fsn.getState().getTrafficGrade());
        this.trafCenter.setIncidentId("");
        this.trafCenter.setDataResType(fsn.getState().getDataResType());
        this.trafCenter.setCenterId(fsn.getCenterId());
        this.trafCenter.setPsdMissValueYn(this.missPsd.getMissValueYn());
        this.trafCenter.setPsdSpeed(this.missPsd.getSpeed());
        this.trafCenter.setKnnSpeed(0);
        this.trafCenter.setKnnCnt(0);
    }

        private int getTrafficGrade(int speed, int gradMinSpeed, int gradMaxSpeed) {
        if (speed < gradMinSpeed) {
            return 3;
        }
        if (speed > gradMaxSpeed) {
            return 1;
        }
        return 2;
    }
    private int getTravelTime(int speed) {
        if (this.length <= 0 || speed < 1) {
            return 2;
        }
        return Math.max(2, Math.round((this.length * 36) / (float)(speed * 10)));
    }
    public boolean fsnTrafficCorrect(TrafficGrade grade) {
        LinkTrafVal val = this.trafFsn;
        if (!val.getState().isState()) {
            return false;
        }

        if ("O".equals(val.getState().getMissValueYn())) {
            // 운영자 입력 소통정보 인 경우
            // 속도값이 0 이상 인 경우 즉, 소통정보가 존재하는 경우(속도값 0은 소통정보 없음)
            // 속도값 상한에 대한 처리를 하지 않고 운영자가 입력한 속도 정보를 그대로 반영한다.
            if (val.getSpeed() <= 0) {
                val.setSpeed(0);
                val.setTravelTime(0);
                val.getState().setTrafficGrade(0);
            }
            else {
                val.setTravelTime(getTravelTime(val.getSpeed()));
//                this.state.setTrafficGrade(getTrafficGrade(this.speed, gradMinSpeed, gradMaxSpeed));
            }
        }
        else {
            // 운영자 입력 소통정보가 아닌경우 즉, 속도는 모두 0 이상임
            val.setSpeed(correctSpeed(val.getSpeed()));
            val.setTravelTime(getTravelTime(val.getSpeed()));
            val.getState().setTrafficGrade(getTrafficGrade(val.getSpeed(), grade.getMinSpeed(), grade.getMaxSpeed()));
        }
        return true;
    }

    public int correctSpeed(int speed) {
        if (speed < this.minSpeed) {
            return this.minSpeed;
        }
        if (speed > this.maxSpeed) {
            return this.maxSpeed;
        }
        return speed;
    }
}
