package kr.gmtc.gw.standstatus.component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import kr.gmt.so.state.StateManager;
import kr.gmtc.gw.comp.rest.vo.RestServiceData;
import kr.gmtc.gw.comp.thread.CustomThread;
import kr.gmtc.gw.standstatus.config.QueueManageBean;
import kr.gmtc.gw.standstatus.database.dto.DataLoadDTO;
import kr.gmtc.gw.standstatus.database.dto.DataLoadHashMap;
import kr.gmtc.gw.standstatus.kafka.vo.AiVideoMetaData;
import kr.gmtc.gw.standstatus.vo.AiAnalyzeStandSttus;
import kr.gmtc.gw.standstatus.vo.AlarmMsgVO;

public class AnalysisStandStatus {
    
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private CustomThread cThread_Analyze_VideoMeta;
    private CustomThread cThread_Analyze_StandSttus;
    private CustomThread cThread_Maping_CctvIDStandNo;

     private LinkedHashMap<String, RestServiceData> map_stand_sttus;

    DateTimeFormatter df_Pattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSS");

    LocalDateTime dt;

    private DataLoadDTO dto;
	private QueueManageBean queMB;
    
    private LinkedBlockingQueue<ArrayList<AiVideoMetaData>> qRecvVideo;
    private LinkedList<RestServiceData> serviceList;


    public AnalysisStandStatus(DataLoadDTO dataLoadDTO, QueueManageBean queMB){
        this.dto = dataLoadDTO;
        this.queMB = queMB;
        initialize();
    }

    public void initialize() {


        qRecvVideo = queMB.getQRecvVideo();
        serviceList = queMB.getServiceList();

        map_stand_sttus = new LinkedHashMap<String, RestServiceData>();

        try {

            cThread_Maping_CctvIDStandNo = new CustomThread("mapingCctvStand", this, CustomThread.NO_SLEEP, this::init_map_stand_sttus, null, false);
            cThread_Analyze_VideoMeta = new CustomThread("makeMapStandSttus", this, CustomThread.NO_SLEEP, this::analysis_Ai_Video_Meta, null, false);
            cThread_Analyze_StandSttus = new CustomThread("analysisStandSttus", this, CustomThread.NO_SLEEP, this::analysis_Stand_Sttus, null, false);            

        } catch (Exception e) {
            logger.error("Start Fail: "+ e.toString());
        }
    }

    public void start() {
		try {
		
            cThread_Maping_CctvIDStandNo.start(Thread.MAX_PRIORITY);
            cThread_Analyze_VideoMeta.start(Thread.NORM_PRIORITY);
            cThread_Analyze_StandSttus.start(Thread.MIN_PRIORITY);

		} catch (Exception e) {
            logger.error("Start Fail: "+ e);
		}
    }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

    private void init_map_stand_sttus() throws InterruptedException{

        if(dto.getDb_CctvList() == null || dto.getDb_CctvList().size() <= 0 ) {
            Thread.sleep(3000);
            return ;
        }

        String sCctv, sStandNo;

        for(DataLoadHashMap cctv : dto.getDb_CctvList()){
            
            sStandNo = cctv.getItemString("STAND_NO");
            sCctv = cctv.getItemString("CCTV_ID");

            if(map_stand_sttus.isEmpty() || map_stand_sttus.get(sCctv) == null){
                map_stand_sttus.put(sCctv, new RestServiceData(sStandNo, sCctv));
            }
        }    

        if(map_stand_sttus.size() != 0){
            logger.info("Stand Sttus HashMap 생성.");
        }else{
            logger.info("Stand Sttus HashMap 생성 실패.");
        }

        Thread.sleep(1000 * (60 * 10)); // 10분
    }



/*
     * Kafka를 통해 수신받은 AI Video Meta(주기장상황분석정보) 데이터 분석
     * Param : cctv List, AI Meta Data
     * Return : LinkedHashMap Map_Stand_sttus
    */
    private void analysis_Ai_Video_Meta() throws InterruptedException{

        if(dto.getDb_CctvList().size() == 0 || qRecvVideo.size() == 0 || map_stand_sttus.size() == 0) {
            
            Thread.sleep(3000);
            return ;
        }

        AiAnalyzeStandSttus aiStandSttus;

        int queSize = qRecvVideo.size();
        
        for(int idx = 0; idx<queSize; idx++){

            //AiVideoMetaData lcData = qRecvVideo.poll();
            //AiVideoMetaData lcData = qRecvVideo.take();

            List<AiVideoMetaData> lcDataList = qRecvVideo.take();
            for( AiVideoMetaData lcData : lcDataList  ){

                if(lcData.getCc_id().equals("123")){
                    String adsf = "adf";
                }
                
                aiStandSttus = new AiAnalyzeStandSttus();

                aiStandSttus.setArcft_stand(lcData.getArcrft_yn());
                aiStandSttus.setBrdg_cnnctd(lcData.getBrdg_cnnctd());
                aiStandSttus.setCrg_dr_opnd(lcData.getCrg_dr_opnd());
                aiStandSttus.setPad_clear(lcData.getPad_clear());
                aiStandSttus.setTwng_cr_cnnctd(lcData.getTwng_cr_cnnctd());
    
                map_stand_sttus.get(lcData.getCc_id()).setAiStandSttus(aiStandSttus);

            }
            
            // 주기장 항공기 상태 초기화
            //map_stand_sttus.get(lcData.getCc_id()).setAircraft_sttus_ty("0");
            
        }

       Thread.sleep(300);

    }

    private void analysis_Stand_Sttus() throws InterruptedException {

        if(qRecvVideo.size() == 0){
            // logger.info("AI Video Mata Data(Kafka) 수신 대기");
            Thread.sleep(3000);
            return ;
        }

        // AI 주기장 상황 분석 매핑
        //analysis_Ai_Video_Meta();

        // 항공기 운항 상태 체크 - 도착 스케줄
        analysis_Stand_Sttus_Arr();

        // 항공기 운항 상태 체크 - 출발 스케줄
        analysis_Stand_Sttus_Dep();
            
        // 서비스큐 데이터 적재
        store_Service_Data();

        Thread.sleep(300);
    }

    private int analysis_Stand_Sttus_Arr() {

        if(map_stand_sttus.size() == 0 || dto.getDb_FltArr().size() == 0) return 0;

        String sCctv, sStandNo, sSttusCD;
        int idx;

        List<DataLoadHashMap> list_arr = dto.getDb_FltArr();


        // 도착예정정보 확인
        // for(DataLoadHashMap fltarr : list_arr){
        for(idx = 0; idx < list_arr.size(); idx++){

            DataLoadHashMap _mfltarr = list_arr.get(idx);

            sSttusCD = "0";
            
            sStandNo = _mfltarr.getItemString("STAND_NO");

            // logger.info("fltarr : " + fltarr.toString());
            //logger.info("ARR-Stand : " + sStandNo);

            sCctv = findCctvID(sStandNo);
            
            if(sCctv.equals("")){
                logger.error("cctv ID Not find : " + sStandNo);
                continue; 
            }

            /* [1]도착예정
                * - 출발 진행중이 이님.
                * - 1순위 : 접근관제 인지 시각이 있음
                * - 2순위 : 활주로 도착시각이 있음
            */

            if( !_mfltarr.getItemString("APP_IN_DT").equals("") || !_mfltarr.getItemString("ACTL_ARR_DT").equals("")){

                sSttusCD = "1";

            }else{
                sSttusCD = "0";
            }

            map_stand_sttus.get(sCctv).setClsgn(_mfltarr.getItemString("CLSGN"));
            map_stand_sttus.get(sCctv).setAircraft_sttus_ty(sSttusCD);

            map_stand_sttus.get(sCctv).setSchdul_id(_mfltarr.getItemString("SCHDUL_ID"));
            map_stand_sttus.get(sCctv).setAc_reg_no(_mfltarr.getItemString("AC_REG_NO"));

            // logger.info("ARR --- StandNo:"+sStandNo + "|" + "cctv:" +sCctv + "|" + "CallSign:"+fltarr.get("CLSGN") + " ["+fltarr.toString()+"]");
        }

        // if(idx > 0 ) logger.info("도착 주기장 :" + (idx +1) + "건 갱신" );

        return idx;

    }

    private int analysis_Stand_Sttus_Dep() {

        if(map_stand_sttus.size() == 0 || dto.getDb_FltDep().size() == 0) return 0;

        String sCctv, sStandNo, sSttusCD;
        int idx;
        int iDepStandTm = 15;

        List<DataLoadHashMap> list_Dep = dto.getDb_FltDep();

        //출발 스케줄 확인
        // for(DataLoadHashMap fltdep : dto.getDb_FltDep()){
        for(idx = 0; idx < list_Dep.size(); idx++ ){

            DataLoadHashMap _mfltdep = list_Dep.get(idx);

            /* [2]PDC발부 전
                * - 예상 주기장 출발 시각 15분 이내.
                * - 실제 주기장 출발 시간이 없음.
                * - PDC발부 시각이 없음.
            */

                /* [3]PDC발부
                * - 예상 주기장 출발 시각 15분 이내.
                * - 실제 주기장 출발 시간이 없음.
                * - PDC발부 시각이 있음.
            */

                /* [4]PUSH-BACK 대기
                * - 예상 주기장 출발 시각 15분 이내.
                * - 실제 주기장 출발 시간이 없음.
                * - PDC발부 시각이 있음.
                * - 출발 승인 대기 시각이 있음(ACTL_CLR_WAIT_DT)
            */

            /* [5]PUSH-BACK 진행 
                * - 실제 주기장 출발 시간이 있음
                * - A-CDM 상태코드 'TAX' 미수신
            */

            /* [9]PUSH-BACK 종료
                * - 실제 주기장 출발 시간이 있음
                * - A-CDM 상태코드 'TAX'가 수신됨
            */

            sSttusCD = "0";

            sStandNo = _mfltdep.getItemString("STAND_NO");

            sCctv = findCctvID(sStandNo);
            
            if(sCctv.equals("")){
                logger.error("cctv ID Not find : " + sStandNo);
                continue; 
            }

            if(sCctv.equals("107")){
                String asdf = "asdfasdf";
            }

            String sRecvTime = _mfltdep.getItemString("EXP_STAND_OFF_DT");
            sRecvTime = sRecvTime.concat("00.000");
            dt = LocalDateTime.parse(sRecvTime, df_Pattern);

            Duration diff = Duration.between(LocalDateTime.now(), dt);

            String aiSttus;

            sSttusCD = "0";
            aiSttus = map_stand_sttus.get(sCctv).getAiStandSttus().getArcft_stand();

            // 예상 주기장 출발 시각 15분 이내, 실제 주기장 출발 시간이 없음.
            // if( aiSttus.equals("Y")){  //AI 상황분석 검증 완료전까지 주석

                if(_mfltdep.getItemString("ACTL_STAND_OFF_DT").equals("")){

                    if(_mfltdep.getItemString("PDC_ISUE_TM").equals("")){
                        sSttusCD = "2"; //[2]PDC발부 전
                    }else{
                        sSttusCD = "3"; //[3]PDC발부
                    }

                    if( !_mfltdep.getItemString("ACTL_CLR_WAIT_DT").equals("")){
                        sSttusCD = "4"; //[4]PUSH-BACK 대기
                    }
                }

                if( !_mfltdep.getItemString("ACTL_STAND_OFF_DT").equals("")){

                    sSttusCD = "5"; //[5]PUSH-BACK 진행

                    if(_mfltdep.getItemString("TAX_YN").equals("Y")){
                        sSttusCD = "6"; //[9]PUSH-BACK 종료
                    }
                }

            // }else{
            //     sSttusCD = "0";
            // }

            map_stand_sttus.get(sCctv).setClsgn(_mfltdep.getItemString("CLSGN"));
            map_stand_sttus.get(sCctv).setAircraft_sttus_ty(sSttusCD);

            map_stand_sttus.get(sCctv).setSchdul_id(_mfltdep.getItemString("SCHDUL_ID"));
            map_stand_sttus.get(sCctv).setAc_reg_no(_mfltdep.getItemString("AC_REG_NO"));

            // logger.info("DEP --- StandNo:"+sStandNo + "|" + "cctv:" +sCctv + "|" + "CallSign:"+fltdep.get("CLSGN") + " ["+fltdep.toString()+"]");
        }


        // if(idx > 0 ) logger.info("출발 주기장 :" + (idx +1) + "건 갱신" );

        return idx;
    }

    

    private void store_Service_Data(){

        if(map_stand_sttus.size() == 0 ) return ;

        LinkedList<RestServiceData> valueList = new LinkedList<RestServiceData>(map_stand_sttus.values());

        // for(int qi=0; qi<scvQcount; qi++) {
        //     serviceList.get(qi).clear();
        //     serviceList.get(qi).addAll(valueList);
        // }

        serviceList.clear();
        serviceList.addAll(valueList);

    }

    private String findCctvID(String sStandNO){

        if(dto.getDb_CctvList().size() <= 0) return "";

        for(DataLoadHashMap cctv : dto.getDb_CctvList()){
            
            if(cctv.getItemString("STAND_NO").equals(sStandNO)){
                return cctv.getItemString("CCTV_ID");
            }
        }

        return "";
    }        


    /////////////////////////////////////////////////////////////////////////////////////////////////////////

}
