package com.tsi.comm.server.process.dbms;

import com.tsi.app.common.app.AppUtils;
import com.tsi.app.common.utils.Elapsed;
import com.tsi.app.common.utils.TimeUtils;
import com.tsi.comm.server.mybatis.TsiDatabaseMapper;
import com.tsi.comm.server.mybatis.vo.*;
import com.tsi.comm.server.process.AbstractTsiCvimWorker;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.LinkedBlockingQueue;

@Slf4j
public class TsiCvimDbmsWorker extends AbstractTsiCvimWorker implements Runnable {

    //private ConcurrentLinkedQueue<AbstractTsiPacket> DATA_QUEUE;
    private final LinkedBlockingQueue<Object> DATA_QUEUE;
    private final TsiDatabaseMapper tsiDatabaseMapper;

    public TsiCvimDbmsWorker(int idx, int qSize) {
        this.idx = idx;
        this.qSize = qSize;
        this.DATA_QUEUE = new LinkedBlockingQueue<>(qSize);
        this.tsiDatabaseMapper = (TsiDatabaseMapper) AppUtils.getBean(TsiDatabaseMapper.class);
    }

    @Override
    public void run() {
        log.info("{} Start. QSIZE: {}", Thread.currentThread().getName(), this.qSize);
        while (true) {
            try {
                Object object = this.DATA_QUEUE.take();
                if (object != null) {
                    process(object);
                }
                else {
                    Thread.yield();
                }
            }
            catch (Exception e) {
                log.error("Exception: {}", e.getMessage());
            }
        }
    }

    /*
     *  작업큐에 데이터 추가
     */
    public boolean add(Object object) {
        boolean offer = false;
        try {
            //offer => full -> return
            //add   => full -> wait
            offer = this.DATA_QUEUE.offer(object);
            if (!offer) {
                log.error("Packet Queue.offer: {}/{}, Queue Full: {} EA, {}, {}",
                        object.getClass().getSimpleName(), this.DATA_QUEUE.size(), this.qSize, object, Thread.currentThread().getName());
            }
        } catch (Exception e) {
            log.error("Packet Queue.offer: Exception: {}, {}, {}", object.toString(), Thread.currentThread().getName(), e.getMessage());
        }
        return offer;
    }

    public void process(Object object) {

        Elapsed elapsed = new Elapsed();
        String job = "Unknown";
        int count = 0;

        if (object instanceof AbstractDbmsVo) {
            AbstractDbmsVo dbmsVo = (AbstractDbmsVo)object;
            if (dbmsVo.getDbmsType() == AbstractDbmsVo.DBMS_TPMS_STAT_1S) {
                this.tsiDatabaseMapper.insertCommTpsHs((CommStatusVo) dbmsVo);
                job = "CommTpHs";
                count = 1;
            }
            else if (dbmsVo.getDbmsType() == AbstractDbmsVo.DBMS_KAFKA_TRANS_HS) {
                this.tsiDatabaseMapper.insertKafkaTransHs((KafkaTransVo) dbmsVo);
                job = "KafkaTransHs";
                count = 1;
            }
            else if (dbmsVo.getDbmsType() == AbstractDbmsVo.DBMS_NODE_STATUS) {
                this.tsiDatabaseMapper.updateNodeStatus((NodeStatusVo)object);
                job = "NodeStatus";
                count = 1;
            }
            else if (dbmsVo.getDbmsType() == AbstractDbmsVo.DBMS_ALARM_OCCR_HS) {
                this.tsiDatabaseMapper.insertAlarmOccrHs((AlarmOccrVo)object);
                job = "AlarmOccr";
                count = 1;
            }
        }
        else {
            log.error("Unknown Object Class: {}", object.getClass().getSimpleName());
        }

        log.info("{}: {} EA. {} {}", job, count, TimeUtils.elapsedTimeStr(elapsed.nanoSeconds()), Thread.currentThread().getName());
    }

    public void report() {
        long avgTime = 0;
        log.info("Packet: Remain Q: {}, Average: {}, {}", this.DATA_QUEUE.size(), TimeUtils.elapsedTimeStr(avgTime), Thread.currentThread().getName());
    }
}
