package com.icomsys.main_vm.biz.rcp.learningTest.service;

import com.icomsys.main_vm.biz.common.common.service.LogService;
import com.icomsys.main_vm.biz.rcp.conversation.nlp.wisenut.service.NlpWisenutService;
import com.icomsys.main_vm.biz.rcp.conversation.nlp.wisenut.vo.NlpSimulationResult;
import com.icomsys.main_vm.biz.rcp.learningTest.SttCode;
import com.selvasai.selvystt.Lvcsr_Lib;
//import com.selvasai.selvystt.model.LVCSR_CHANNEL_STAT;
import com.selvasai.selvystt.model.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.sl.draw.geom.Guide;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.annotation.Resource;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

@Service
@Slf4j
@RequiredArgsConstructor
public class LearningTestInSttService {
    public SttCode sttCode;
    public String doTestSvc(String cHost, int uPort, String fileName, int ModelID) {
        Lvcsr_Lib lib = new Lvcsr_Lib();
        LVCSR_RESULT ret = null;

        LocalDateTime date = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");

        String pcmPath = "/logs/was/aicb/cinnamon_ui/files/stttest/" + formatter.format(date) + File.separator;

        try {
            ret = lib.ASR_SVC_OPEN(cHost, uPort);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_OPEN ERROR] : " + ret);
                sttCode = SttCode.FAIL_OPEN;
                return "ASR_SVC_OPEN ERROR";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_OPEN RETURN] : " + ret);
            }

            LVCSR_DATA_AUTHENTICATION authInfo = new LVCSR_DATA_AUTHENTICATION();
            String pAuthentication = "ModelUpdate";
            authInfo.setAuthentication(pAuthentication);
            ret = lib.ASR_SVC_SET_AUTH(authInfo);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_AUTH RETURN] : " + ret);
                sttCode = SttCode.FAIL_AUTH;
                return "ASR_SVC_AUTH RETURN";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_AUTH RETURN] : " + ret + " ID: " + pAuthentication);
            }

            LVCSR_DATA_TRANSACTION transInfo = new LVCSR_DATA_TRANSACTION();
            UUID TransactionId = UUID.randomUUID();
            String pTransaction = pAuthentication + "_" + TransactionId.toString();
            transInfo.setTransactionId(pTransaction);
            ret = lib.ASR_SVC_SET_TRANS(transInfo);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_SET_TRANS RETURN] : " + ret);
                sttCode = SttCode.FAIL_SET_TRANS;
                return "ASR_SVC_SET_TRANS RETURN";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_SET_TRANS RETURN] : " + ret);
            }

            LVCSR_DATA_SOCKTIMEOUT socktimeinfo = new LVCSR_DATA_SOCKTIMEOUT();
            socktimeinfo.setConnTimeOut(10);
            socktimeinfo.setReadTimeOut(240);
            ret = lib.ASR_SVC_SET_SOCKTIME(socktimeinfo);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_SET_SOCKTIME ERROR] : " + ret);
                sttCode = SttCode.FAIL_SET_SOCKTIME;
                return "ASR_SVC_SET_SOCKTIME ERROR";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_SET_SOCKTIME RETURN] : " + ret);
            }

            ret = lib.ASR_SVC_RECG_OPEN();
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_RECG_OPEN ERROR] : " + ret);
                sttCode = SttCode.FAIL_RECG_OPEN;
                return "ASR_SVC_RECG_OPEN ERROR";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_RECG_OPEN RETURN] : " + ret);
            }

            LVCSR_DATA_MODEL modelinfo = new LVCSR_DATA_MODEL();
            ret = lib.ASR_SVC_RECG_LIST_VIEW(modelinfo);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_RECG_LIST_VIEW ERROR] : " + ret);
                sttCode = SttCode.FAIL_RECG_LIST_VIEW;
                return "ASR_SVC_RECG_LIST_VIEW ERROR";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_RECG_LIST_VIEW RETURN] : " + ret);
            }
            if(modelinfo.getModelCnt() > 0) {
                long rsltCnt = modelinfo.getModelCnt();
                for(int i=0 ; i < rsltCnt ; i++) {
                    long nModelID = modelinfo.getModelInfo()[i].getModelID();
                    String pModelName = modelinfo.getModelInfo()[i].getModelName();
                    long nModelType = modelinfo.getModelInfo()[i].getModelType();
                    long nSamplingRate = modelinfo.getModelInfo()[i].getSamplingRate();
                    long nKwdCnt = modelinfo.getModelInfo()[i].getKwdCnt();
                    log.info(String.format("MODEL 결과 #%d[%d, %s, %d, %d]", i+1, nModelID, pModelName, nModelType, nSamplingRate));

                    for(int j=0 ; j < nKwdCnt ; j++) {
                        long nKwdID = modelinfo.getModelInfo()[i].getKwdInfo()[j].getKwdID();
                        String pKwdName = modelinfo.getModelInfo()[i].getKwdInfo()[j].getKwdName();
                        log.info(String.format("KWD 결과 #%d:#%d[%d, %s]", i+1, j+1, nKwdID, pKwdName));
                    }
                }
            }



            LVCSR_DATA_INFO datainfo = new LVCSR_DATA_INFO();
            datainfo.setModelId(ModelID);
            datainfo.setKwdId(-1);
            datainfo.setCodecType(LVCSR_TYPE_CODEC.CODEC_RAW_8K);
            datainfo.setCharSet(LVCSR_SET_CHARSET.CHAR_SET_EUCKR);
            datainfo.setEpdUsed(LVCSR_USED_EPD.SERVER_EPD_USED_ON);
            datainfo.setScoreUsed(LVCSR_USED_SCORE.SCORE_USED_ON);
            datainfo.setAsyncMidRstUsed(LVCSR_USED_ASYNC_MID_RESULT.ASYNC_MIDRST_USED_ON);
            ret = lib.ASR_SVC_RECG_SET_LIST(datainfo);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_RECG_SET_LIST ERROR] : " + ret);
                sttCode = SttCode.FAIL_RECG_SET_LIST;
                return "ASR_SVC_RECG_SET_LIST ERROR";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_RECG_SET_LIST RETURN] : " + ret);
            }

            LVCSR_DATA_TIMEOUT datatimeout = new LVCSR_DATA_TIMEOUT();
            datatimeout.setStartTimeout(6);
            datatimeout.setDurationTimeout(300);
            ret = lib.ASR_SVC_RECG_SET_EPD_TIMEOUT(datatimeout);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_RECG_SET_EPD_TIMEOUT ERROR] : " + ret);
                sttCode = SttCode.FAIL_RECG_SET_EPD_TIMEOUT;
                return "ASR_SVC_RECG_SET_EPD_TIMEOUT ERROR";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_RECG_SET_EPD_TIMEOUT RETURN] : " + ret);
            }

            LVCSR_DATA_MARGIN datamargin = new LVCSR_DATA_MARGIN();
            datamargin.setEpdMargin(0.7f);
            ret = lib.ASR_SVC_RECG_SET_EPD_MARGIN(datamargin);
            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info("[ASR_SVC_RECG_SET_EPD_MARGIN ERROR] : " + ret);
                sttCode = SttCode.FAIL_RECG_SET_EPD_MARGIN;
                return "ASR_SVC_RECG_SET_EPD_MARGIN ERROR";
            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_RECG_SET_EPD_MARGIN RETURN] : " + ret);
            }

            FileInputStream fileInputStream = null;
            DataInputStream dataInputStream = null;
            try {
                File file = new File(pcmPath + fileName);
                fileInputStream = new FileInputStream(file);
                dataInputStream = new DataInputStream(fileInputStream);

                byte[] buff = new byte[1600];	//버퍼 크기는 생성되는 크기에 따라 설정 가능

                LVCSR_EPD_INFO epdinfo = new LVCSR_EPD_INFO();
                int nLen = 0;
                int bButtonComplete = 0;

                while ( (nLen = dataInputStream.read(buff)) != -1 ) {
                    ret = lib.ASR_SVC_RECG_DATA(buff, nLen, bButtonComplete, epdinfo);
                    if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                        if (LVCSR_EPD_STAT.DURATION_TIME_OVER == epdinfo.getOutput() || LVCSR_EPD_STAT.EPD_FOUND == epdinfo.getOutput()) {
                            log.info("[ASR_SVC_RECG_DATA RECV] : " + epdinfo.getOutput());
                            break;
                        }
                        if (LVCSR_EPD_STAT.RECEIV_OK == epdinfo.getOutput() || LVCSR_EPD_STAT.RECEIV_OK_SPEECH == epdinfo.getOutput() || LVCSR_EPD_STAT.SECTION_FOUND == epdinfo.getOutput()) {
                            LVCSR_RECOG_MID_RESULT resultmidinfo = new LVCSR_RECOG_MID_RESULT();
                            ret = lib.ASR_SVC_RECG_MID_PROC(resultmidinfo);
                            if (ret == LVCSR_RESULT.LVCSR_FAIL) {
                                log.info(String.format("인식 결과 REJCT2 [%s]", ret));
                            } else if (ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                                log.info("[ASR_SVC_RECG_MID_PROC RETURN] : " + ret + " 문장길이:" + resultmidinfo.getResultLen() + " 개수:" + resultmidinfo.getCount());
                                if(resultmidinfo.getResultLen() > 0) {
                                    log.info(String.format("인식 중간 결과 문장 [%s]", resultmidinfo.getStrResult()));
                                }
                                long rsltCnt = resultmidinfo.getCount();
                                if(rsltCnt > 0) {
                                    for(int i=0 ; i < rsltCnt ; i++) {
                                        log.info(String.format("인식 중간 결과 #%d[%s, %s, %d, %d]", i+1, fileName, resultmidinfo.getDataResult()[i].getStrToken(), resultmidinfo.getDataResult()[i].getStart(), resultmidinfo.getDataResult()[i].getEnd()));

                                        long phCnt = resultmidinfo.getDataResult()[i].getResultPhCnt();
                                        for(int j=0 ; j < phCnt ; j++) {
                                            String phonemeResultStr = resultmidinfo.getDataResult()[i].getResultPhoneme()[j].getStrPhToken();
                                            if (phonemeResultStr != null) {
                                                log.info(String.format("인식 중간 결과[#%d]#%d[%s, %d]", i+1, j+1, resultmidinfo.getDataResult()[i].getResultPhoneme()[j].getStrPhToken(), resultmidinfo.getDataResult()[i].getResultPhoneme()[j].getDuration()));
                                            } else {
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            log.info("[ASR_SVC_RECG_DATA RECV] : " + epdinfo.getOutput());
                            continue;
                        }
                    }
                }
                dataInputStream.close();
                fileInputStream.close();

                if (-1 == nLen || 0 == nLen) {
                    bButtonComplete = 1;
                    lib.ASR_SVC_RECG_DATA(buff, 0, bButtonComplete, epdinfo);
                    if (LVCSR_EPD_STAT.EPD_FOUND != epdinfo.getOutput()) {
                        log.info(String.format("인식 결과 EPD Not Found [%s]", fileName));
                        sttCode = SttCode.FAIL_EPD_NOT_FOUND;
                        return "인식 결과 EPD Not Found";
                    } else {
                        log.info("[ASR_SVC_RECG_DATA RECV] : " + epdinfo.getOutput());
                    }
                }

            } catch ( IOException e ) {
                throw e;
            } finally {
                if ( dataInputStream != null ) try { dataInputStream.close(); } catch (Exception e) { }
                if ( fileInputStream != null ) try { fileInputStream.close(); } catch (Exception e) { }
            }

            LVCSR_RECOG_RESULT resultinfo = new LVCSR_RECOG_RESULT();
            LVCSR_RESULT proc_ret = lib.ASR_SVC_RECG_STR_PROC(resultinfo);
            if (proc_ret == LVCSR_RESULT.LVCSR_FAIL) {
                log.info(String.format("인식 결과 REJCT2 [%s]", fileName));
                return "인식 결과 REJCT2 [%s]" + fileName;
            } else if (proc_ret == LVCSR_RESULT.LVCSR_SUCCESS) {
                log.info("[ASR_SVC_RECG_PROC RETURN] : " + ret + " 문장길이:" + resultinfo.getResultLen() + " 개수:" + resultinfo.getCount()  + " ADDR 사용여부:" + resultinfo.getADDRUsed() + " KWD 개수:" + resultinfo.getKWDCount());
                long rsltLen = resultinfo.getResultLen();
                if (rsltLen > 0) {
                    log.info(String.format("인식 결과 [%s] 스코어[%4.3f] 시작ms[%d] 끝ms[%d]", resultinfo.getStrResult(), resultinfo.getConfidScore(), resultinfo.getResultEPD().getStart(), resultinfo.getResultEPD().getEnd()));
                    sttCode = SttCode.SUCCESS;
                    return resultinfo.getStrResult();
                }
                long rsltCnt = resultinfo.getCount();
                if(rsltCnt > 0) {
                    for(int i=0 ; i < rsltCnt ; i++) {
                        log.info(String.format("인식 단어 결과 #%d[%s, %s, %d, %d]", i+1, fileName, resultinfo.getDataResult()[i].getStrToken(), resultinfo.getDataResult()[i].getStart(), resultinfo.getDataResult()[i].getEnd()));

                        long phCnt = resultinfo.getDataResult()[i].getResultPhCnt();
                        for(int j=0 ; j < phCnt ; j++) {
                            String phonemeResultStr = resultinfo.getDataResult()[i].getResultPhoneme()[j].getStrPhToken();
                            if (phonemeResultStr != null) {
                                log.info(String.format("인식 음소 결과[#%d]#%d[%s, %d]", i+1, j+1, resultinfo.getDataResult()[i].getResultPhoneme()[j].getStrPhToken(), resultinfo.getDataResult()[i].getResultPhoneme()[j].getDuration()));
                            } else {
                                break;
                            }
                        }
                    }
                }

                long rsltSentCnt = resultinfo.getSentCount();
                if(rsltSentCnt > 0) {
                    for(int i=0 ; i < rsltSentCnt ; i++) {
                        log.info(String.format("문장 결과 #%d[%s, %s, %d, %d]", i+1, fileName, resultinfo.getDataSentResult()[i].getStrToken(), resultinfo.getDataSentResult()[i].getStart(), resultinfo.getDataSentResult()[i].getEnd()));

                        long phCnt = resultinfo.getDataSentResult()[i].getResultPhCnt();
                        for(int j=0 ; j < phCnt ; j++) {
                            String phonemeResultStr = resultinfo.getDataSentResult()[i].getResultPhoneme()[j].getStrPhToken();
                            if (phonemeResultStr != null) {
                                log.info(String.format("문장 결과[#%d]#%d[%s, %d]", i+1, j+1, resultinfo.getDataSentResult()[i].getResultPhoneme()[j].getStrPhToken(), resultinfo.getDataSentResult()[i].getResultPhoneme()[j].getDuration()));
                            } else {
                                break;
                            }
                        }
                    }
                }

                long addrUsed = resultinfo.getADDRUsed();
                if (addrUsed > 0) {
                    log.info(String.format("주소 결과 보정 유형 [%d] 보정 주소[%s] 기본주소[%s] 상세주소[%s]", resultinfo.getResultADDR().getCorrectType(), resultinfo.getResultADDR().getZipcode(), resultinfo.getResultADDR().getStrMainAddress(), resultinfo.getResultADDR().getStrAuxAddress()));
                    log.info(String.format("주소 결과 시/도 [%s] 시/군/구 main[%s] 시/군/구 sub[%s] 읍/면/동[%s] 리[%s] 지번[%s] 도로명[%s] 건물번호[%s] POI명[%s]", resultinfo.getResultADDR().getSepAddr().getStrSido(), resultinfo.getResultADDR().getSepAddr().getStrSigunguMain(), resultinfo.getResultADDR().getSepAddr().getStrSigunguSub(), resultinfo.getResultADDR().getSepAddr().getStrDong(), resultinfo.getResultADDR().getSepAddr().getStrLi(), resultinfo.getResultADDR().getSepAddr().getStrJibun(), resultinfo.getResultADDR().getSepAddr().getStrRoadName(), resultinfo.getResultADDR().getSepAddr().getStrBldgNo(), resultinfo.getResultADDR().getSepAddr().getStrPoiName()));
                }

                long kwdCnt = resultinfo.getKWDCount();
                if(kwdCnt > 0) {
                    for(int x=0 ; x < kwdCnt ; x++) {
                        String kwdToken = resultinfo.getResultKWD()[x].getStrToken().toString();
                        log.info(String.format("KWD 결과 #%d[%s, %s, %d, %d, %4.3f]", x+1, kwdToken, resultinfo.getResultKWD()[x].getStrSymbol(), resultinfo.getResultKWD()[x].getStart(), resultinfo.getResultKWD()[x].getEnd(), resultinfo.getResultKWD()[x].getScore()));
                    }
                }
            }

        } catch(Exception e) {
            System.out.println(e);
        } finally {
            try {
                lib.ASR_SVC_RECG_CLOS();
            } catch(Exception e) { }
            try {
                lib.ASR_SVC_CLOS();
            } catch(Exception e) { }
        }
        return "";
    }

}
