package com.its.vms.service;

import com.its.app.AppUtils;
import com.its.app.utils.Elapsed;
import com.its.app.utils.SysUtils;
import com.its.vms.config.ApplicationConfig;
import com.its.vms.dao.mapper.VmsCtlrMapper;
import com.its.vms.domain.NET;
import com.its.vms.entity.TbVmsCtlr;
import com.its.vms.entity.TbVmsCtlrStts;
import com.its.vms.dto.TbVmsCtlrDto;
import com.its.vms.process.DbmsData;
import com.its.vms.process.DbmsDataProcess;
import com.its.vms.process.DbmsDataType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

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

    private final ApplicationConfig config;
    private final AppRepositoryService repoService;
    private final VmsCtlrMapper mapper;
    private int historyMin;

    @PostConstruct
    private void init() {
        log.info("VmsCtlrService.init: Start.");
        this.historyMin = -1;
        log.info("VmsCtlrService.init: ..End.");
    }

    public void loadDb() {
        loadCtlrInfo();
        loadCtlrSttsInfo();
    }

    public void loadCtlrInfo() {
        Elapsed elapsed = new Elapsed();
        this.repoService.initCtlrInfo();

        try {
            List<TbVmsCtlr> infoList  = this.mapper.selectAll();
            log.info("VmsCtlrService.loadCtlrInfo: {} EA", infoList.size());
            for (TbVmsCtlr dto : infoList) {
                log.info("VmsCtlrService.loadCtlrInfo: {}.", dto);
                TbVmsCtlrDto vmsObj = dto.toDto();
                if (vmsObj.getCtlrId().trim().equals("")) {
                    log.error("VmsCtlrService.loadCtlrInfo: Controller Ip Address Error: {}.", vmsObj);
                    continue;
                }

                vmsObj.setGroupNo(0L);

                this.repoService.putCtrlMap(vmsObj);
                this.repoService.putIpAddrMap(vmsObj);
                vmsObj.getStts().initUnknown();

                if (vmsObj.getMaxPhaseNum() > this.config.getMaxDownloadForms()) {
                    log.error("VmsCtlrService.loadCtlrInfo: VMS {} Download Form Size Error: {}/{}.", vmsObj.getVmsCtlrNmbr(), vmsObj.getMaxPhaseNum(), this.config.getMaxDownloadForms());
                    vmsObj.setMaxPhaseNum(this.config.getMaxDownloadForms());
                }
                vmsObj.setLocalFormDir(this.config.getFtpFormDir() + File.separator + vmsObj.getVmsCtlrNmbr() + File.separator);
                vmsObj.setFtpFormDir(ApplicationConfig.FTP_FORM + File.separator + vmsObj.getVmsCtlrNmbr() + File.separator);
                vmsObj.setFtpDownload(true);

                this.config.makeDirectory(vmsObj.getLocalFormDir(), "VMS " + vmsObj.getVmsCtlrNmbr() + " Directory.");
            }
        }
        catch (Exception e) {
            log.error("VmsCtlrService.loadCtlrInfo: {}.", e.toString());
        }

        this.repoService.getCtlrMap().forEach((key, obj) -> {
            log.info("VmsCtlrService.loadCtlrInfo:: {}.", obj.toString());
        });
        log.info("VmsCtlrService.loadCtlrInfo: {} ms.", elapsed.milliSeconds());
    }

    public void loadCtlrSttsInfo() {
        Elapsed elapsed = new Elapsed();
        try {
            List<TbVmsCtlrStts> infoList  = this.mapper.selectCtlrStts();
            log.info("VmsCtlrService.loadCtlrSttsInfo: {} EA", infoList.size());
            infoList.forEach(dto -> {
                TbVmsCtlrDto obj = this.repoService.getCtrlMap(dto.getVmsCtlrNmbr());
                if (obj == null) {
                    log.error("VmsCtlrService.loadCtlrSttsInfo: Not Found VMS {}.", dto.getVmsCtlrNmbr());
                    return;
                }
                obj.getStts().updateStts(dto);
            });
        }
        catch (Exception e) {
            log.error("VmsCtlrService.loadCtlrSttsInfo: {}.", e.toString());
        }
        log.info("VmsCtlrService.loadCtlrSttsInfo: {} ms.", elapsed.milliSeconds());
    }

    public void updateCtlrStts(boolean isRun, TbVmsCtlrDto AObj) {
        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<TbVmsCtlrStts> ctlrSttsList = Collections.synchronizedList(new ArrayList<>());
        String UPDT_DT = SysUtils.getSysTime();
        int normal = 0;
        int error  = 0;

        for (Map.Entry<Long, TbVmsCtlrDto> e : this.repoService.getCtlrMap().entrySet()) {
            TbVmsCtlrDto obj = e.getValue();
            if (AObj != null && !Objects.equals(AObj.getVmsCtlrNmbr(), obj.getVmsCtlrNmbr())) {
                continue;
            }

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

            if (isRun) {
                ctlrSttsList.add(obj.getStts());
            }
            else {
                this.mapper.updateCtlrStts(obj.getStts());
                if (insHs) {
                    this.mapper.insertCtlrSttsHs(obj.getStts());
                }
            }
        }

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

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

}
