package com.its.dsrc.service;

import com.its.app.AppUtils;
import com.its.app.utils.SysUtils;
import com.its.dsrc.dao.mapper.RseCtlrMapper;
import com.its.dsrc.entity.TbRseCtlr;
import com.its.dsrc.entity.TbRseCtlrStts;
import com.its.dsrc.entity.TbRseObuNonCrypt;
import com.its.dsrc.global.AppRepository;
import com.its.dsrc.process.DbmsData;
import com.its.dsrc.process.DbmsDataProcess;
import com.its.dsrc.process.DbmsDataType;
import com.its.dsrc.vo.NET;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;

@Slf4j
@Service
@Transactional(rollbackFor = {Exception.class})
public class RseCtlrService {

    private RseCtlrMapper rseCtlrMapper;
    private int historyMin;

    @PostConstruct
    private void init() {
        log.info("RseCtlrService.init: Start.");
        this.rseCtlrMapper = (RseCtlrMapper) AppUtils.getBean(RseCtlrMapper.class);
        this.historyMin = -1;
        log.info("RseCtlrService.init: ..End.");
    }

    public void loadDb() {
        loadRseCtlr();
        loadRseObjNonCrypt();
    }

    public void initRseCtlr() {
        try {
            for (Map.Entry<String, TbRseCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
                // 제어기가 삭제됐다고 초기화
                TbRseCtlr obj = e.getValue();
                obj.setDEL_YN("Y");
            }
        }
        catch (Exception e) {
            log.error("RseCtlrService.initRseCtlr: Exception: {}", e.toString());
        }
    }


    public void loadRseCtlr() {
        initRseCtlr();
        try {
            List<TbRseCtlr> infoList  = this.rseCtlrMapper.selectAll();
            log.info("rseCtlrMapper.selectAll(), {} EA", infoList.size());
            for (TbRseCtlr obj : infoList) {
                obj.setRSE_CTLR_IP(obj.getRSE_CTLR_IP().trim());  // 빈문자열 삭제
                if (obj.getRSE_CTLR_IP() != null && obj.getRSE_CTLR_IP().length() > 0) {

                    obj.getStts().setRSE_CTLR_NMBR(obj.getID());
                    obj.getStts().initUnknown();

                    AppRepository.getInstance().getCtlrMap().put(obj.getID(), obj);
                    AppRepository.getInstance().getCtlrIpMap().put(obj.getRSE_CTLR_IP(), obj);
                }
            }
        }
        catch (Exception e) {
            log.error("rseCtlrMapper.selectAll: {}", e.toString());
        }

        for (Map.Entry<String, TbRseCtlr> obj : AppRepository.getInstance().getCtlrMap().entrySet()) {
            log.info(obj.toString());
        }
    }

    public void loadRseObjNonCrypt() {
        try {
            AppRepository.getInstance().rseObuNonCryptList.clear();
            AppRepository.getInstance().rseObuNonCryptList = this.rseCtlrMapper.selectRseObuNonCryptList();
        }
        catch (Exception e) {
            log.error("rseCtlrMapper.selectRseObuNonCryptList: {}", e.toString());
        }
        for (TbRseObuNonCrypt vo : AppRepository.getInstance().rseObuNonCryptList) {
            log.debug(vo.toString());
        }
    }

    public void updateCtlrStts(boolean isRun) {
        String keyData = "unit";
        boolean insHs = false;
        Calendar cal = Calendar.getInstance();
        int min = cal.get(Calendar.MINUTE);
        if ((min % 5) == 0 && this.historyMin != min) {
            insHs = true;
            this.historyMin = min;
        }

        //제어기 상태정보 업데이트
        List<TbRseCtlrStts> ctlrSttsList = Collections.synchronizedList(new ArrayList<>());
        String UPDT_DT = SysUtils.getSysTime();
        int normal = 0;
        int error  = 0;
        for (Map.Entry<String, TbRseCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
            TbRseCtlr obj = e.getValue();
            obj.getStts().setUPDT_DT(UPDT_DT);

            if (isRun && obj.getNetState() >= NET.LOGINED && obj.getChannel() != null) {
                //제어기 통신정상
                normal++;
                obj.getStts().setCMNC_STTS_CD("CMS0");
            }
            else {
                //제어기 통신이상
                error++;
                obj.getStts().initError();
            }

            if (isRun) {
                ctlrSttsList.add(obj.getStts());
            }
            else {
                this.rseCtlrMapper.updateRseCtlrStts(obj.getStts());
                if (insHs) {
                    this.rseCtlrMapper.insertRseCtlrSttsHs(obj.getStts());
                }
            }
        }

        // 제어기 상태정보 DB 업데이트
        if (ctlrSttsList.size() > 0) {
            DbmsDataProcess dbmsDataProcess = (DbmsDataProcess) AppUtils.getBean(DbmsDataProcess.class);
            dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_CTLR_STTS, insHs, ctlrSttsList));
        }

        log.info("RseCtlrService.updateCtlrStts: total {}, normal {}, error {}", normal + error, normal, error);
    }

    public void monitoringSession() {
        long currMilliSeconds = System.currentTimeMillis();
        for (Map.Entry<String, TbRseCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
            TbRseCtlr obj = e.getValue();
            if (obj.getNetState() >= NET.LOGIN_REQ && obj.getChannel() != null) {
                // 주차정보시스템 통신정상
                long recvTimout = currMilliSeconds - obj.getLastRecvTime();
                if (recvTimout > 15*1000) {
                    log.error("Idle timeout: {}, ipAddr={}, Idle={} sec.", obj.getID(), obj.getRSE_ID(), (int)(recvTimout/1000L));
                    obj.setLastRecvTime();
                    obj.sendFrED();
                }

            }
        }
    }
}
