package com.tsi.comm.server.mybatis;

import com.tsi.app.common.app.AppUtils;
import com.tsi.app.common.utils.TimeUtils;
import com.tsi.comm.server.mybatis.vo.*;
import com.tsi.comm.server.repository.TsiAlarmManager;
import com.tsi.comm.server.repository.TsiNodeAddManager;
import com.tsi.comm.server.repository.TsiNodeManager;
import com.tsi.comm.server.vo.TsiAlarmConfigVo;
import com.tsi.comm.server.vo.TsiNodeAddDetailVo;
import com.tsi.comm.server.vo.TsiNodeAddVo;
import com.tsi.comm.server.vo.TsiNodeVo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

@Slf4j
@Getter
@Setter
@Service
public class TsiDatabaseService {

    private TsiDatabaseMapper tsiDatabaseMapper;

    public TsiDatabaseService() {
    }

    @PostConstruct
    void init() {
        this.tsiDatabaseMapper = (TsiDatabaseMapper) AppUtils.getBean(TsiDatabaseMapper.class);
        initDatabase();
        loadDatabase();
    }

    public void loadAlarmConfig() {
        String TAG = "loadAlarmConfig";
        long startTime = System.nanoTime();

        List<AlarmConfigVo> objLists = this.tsiDatabaseMapper.getAlarmConfig();
        for (AlarmConfigVo obj : objLists) {
            TsiAlarmConfigVo alarm = TsiAlarmManager.getInstance().get(obj.getAlarmCode());
            if (alarm != null) {
                alarm.setDesc(obj.getDesc());
                alarm.setValue(obj.getValue());
                alarm.setUseYn(obj.getUseYn().equals("Y"));
            }
            else {
                alarm = new TsiAlarmConfigVo();
                alarm.setAlarmCode(obj.getAlarmCode());
                alarm.setDesc(obj.getDesc());
                alarm.setValue(obj.getValue());
                alarm.setUseYn(obj.getUseYn().equals("Y"));
                TsiAlarmManager.getInstance().put(obj.getAlarmCode(), alarm);
            }
        }

        log.info("{}: ..end. {}/{} EA. {}", TAG, objLists.size(), TsiAlarmManager.getInstance().size(), TimeUtils.elapsedTime(startTime));
    }

    public void initDatabase() {
        int result = this.tsiDatabaseMapper.insertNodeStatusInitialize();
        updateNodeStatusTerm();
        log.info("init database: {} EA", result);
    }

    public void loadDatabase() {
        loadTsiNode();
        loadTsiNodeAdd();
        loadAlarmConfig();
    }

    private void loadTsiNode() {
        String TAG = "loadTsiNode";
        long startTime = System.nanoTime();

        TsiNodeManager.getInstance().beforeLoading();

        boolean installed;
        TsiNodeVo node;

        List<NodeVo> objLists = this.tsiDatabaseMapper.getNodeInfoList();
        for (NodeVo obj : objLists) {
            installed = obj.getUseYn().equals("Y");
            node = TsiNodeManager.getInstance().get(obj.getNodeId());
            if (node != null) {
                node.setCheckInstalled(installed);
                node.setSendTest(obj.getTestYn().equals("Y"));
                node.setSendNode(obj.getNodeYn().equals("Y"));
                node.setSendCvim(obj.getCvimYn().equals("Y"));
                node.setRegistered(true);
            }
            else {
                node = new TsiNodeVo(obj.getNodeId(), obj.getTestYn().equals("Y"), obj.getNodeYn().equals("Y"), obj.getCvimYn().equals("Y"));
                node.setRegistered(true);
                node.setCheckInstalled(installed);
                TsiNodeManager.getInstance().put(obj.getNodeId(), node);
            }
        }

        TsiNodeManager.getInstance().afterLoading();

        log.info("{}: ..end. {}/{} EA. {}", TAG, objLists.size(), TsiNodeManager.getInstance().size(), TimeUtils.elapsedTime(startTime));
    }

    private void loadTsiNodeAdd() {
        String TAG = "loadTsiNodeAdd";
        long startTime = System.nanoTime();

        // 연등지 노드정보 조회
        long originNodeId;
        TsiNodeVo orgTsiNodeVo;

        List<NodeAddVo> objLists = this.tsiDatabaseMapper.getNodeAddInfoList();
        for (NodeAddVo obj : objLists) {
            originNodeId = obj.getOriginNodeId();
            orgTsiNodeVo = TsiNodeManager.getInstance().get(originNodeId);
            if (orgTsiNodeVo == null) {
                // 등록안된 Original Node 를 참조하는 경우
                log.error("Not found origin_node_id: {}", originNodeId);
                orgTsiNodeVo = new TsiNodeVo(originNodeId, true, true, true);
                orgTsiNodeVo.setCheckInstalled(true);
                orgTsiNodeVo.setRegistered(false);
                orgTsiNodeVo.setAddNodeEnabled(true);
                TsiNodeManager.getInstance().put(originNodeId, orgTsiNodeVo);   // 신규로 추가해 준다
            }
            else {
                orgTsiNodeVo.setAddNodeEnabled(true);
            }

            TsiNodeAddVo tsiNodeAddVo = new TsiNodeAddVo();
            tsiNodeAddVo.setOriginNodeId(originNodeId);

            for (int ii = 0; ii < obj.getAddDetailList().size(); ii++) {
                NodeAddDetailVo nodeAddDetailVo = obj.getAddDetailList().get(ii);

                Long nodeId = nodeAddDetailVo.getNodeId();

                TsiNodeAddDetailVo tsiNodeAddDetailVo = new TsiNodeAddDetailVo();
                TsiNodeVo addNodeVo = TsiNodeManager.getInstance().get(nodeId);
                if (addNodeVo == null) {
                    // 등록안된 Node 인 경우
                    log.error("Not found add_node_id: {}", nodeId);
                    addNodeVo = new TsiNodeVo(originNodeId, orgTsiNodeVo.isSendTest(), orgTsiNodeVo.isSendNode(), orgTsiNodeVo.isSendCvim());
                    addNodeVo.setCheckInstalled(true);
                    addNodeVo.setRegistered(false);
                    TsiNodeManager.getInstance().put(nodeId, addNodeVo);    // 신규로 추가해 준다
                }

                tsiNodeAddDetailVo.setNodeId(nodeId);
                tsiNodeAddDetailVo.setOriginDirCode(nodeAddDetailVo.getOriginDirCode());
                tsiNodeAddDetailVo.setAddNodeOrder(nodeAddDetailVo.getAddNodeOrder());
                tsiNodeAddDetailVo.setAddDirCode(nodeAddDetailVo.getAddDirCode());  // 배열로 저장한다.
                tsiNodeAddDetailVo.setNodeObj(addNodeVo);

                tsiNodeAddVo.getAddNodeMap().put(tsiNodeAddDetailVo.getOriginDirCode()*1000 + tsiNodeAddDetailVo.getAddNodeOrder(), tsiNodeAddDetailVo);
                if (tsiNodeAddDetailVo.getNodeObj() != null) {
                    //log.error("    {}, {}, {}", nodeAddVo.getOriginNodeId(), nodeId, detailVo.getNodeId());
                }
            }

            orgTsiNodeVo.setTsiNodeAddVo(tsiNodeAddVo);

            TsiNodeAddManager.getInstance().put(tsiNodeAddVo.getOriginNodeId(), tsiNodeAddVo);
        }

        log.info("{}: ..end. {} EA. {}", TAG, TsiNodeAddManager.getInstance().size(), TimeUtils.elapsedTime(startTime));
    }

    public void updateNodeStatusTerm() {
        int result = this.tsiDatabaseMapper.updateNodeStatusTerm();
        log.info("update node status term: {} EA", result);
    }
    public int insertAlarmOccrHs(AlarmOccrVo vo) {
        int res = 0;
        try {
            res = this.tsiDatabaseMapper.insertAlarmOccrHs(vo);
        }
        catch(Exception e) {
            log.error("{}", e.getMessage());
        }
        return res;
    }
    public int updateProcessState(int flag) {
        int res = 0;
        try {
            if (flag == 0) {
                res = this.tsiDatabaseMapper.updateProcessStatusStart(TsiAlarmManager.getInstance().getProcessStateVo());
            }
            else if (flag == 1) {
                res = this.tsiDatabaseMapper.updateProcessStatusRun(TsiAlarmManager.getInstance().getProcessStateVo());
            }
            else {
                res = this.tsiDatabaseMapper.updateProcessStatusStop(TsiAlarmManager.getInstance().getProcessStateVo());
            }
        }
        catch(Exception e) {
            log.error("{}", e.getMessage());
        }
        return res;
    }
}
