package com.tsi.comm.server.scheduler;

import com.tsi.app.common.utils.Elapsed;
import com.tsi.app.common.utils.TimeUtils;
import com.tsi.comm.server.config.TraceConfig;
import com.tsi.comm.server.config.TsiCvimServerConfig;
import com.tsi.comm.server.kafka.KafkaConsumerService;
import com.tsi.comm.server.kafka.KafkaProducerService;
import com.tsi.comm.server.mybatis.TsiDatabaseService;
import com.tsi.comm.server.repository.TsiAlarmManager;
import com.tsi.comm.server.repository.TsiReportManager;
import com.tsi.comm.server.repository.TsiTpmsManager;
import com.tsi.comm.server.vo.TsiAlarmConfigVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Slf4j
@EnableScheduling
@AllArgsConstructor
@Component
public class TsiCommScheduler {

    private final TraceConfig trace;
    private final TsiCvimServerConfig config;
    private final TsiReportManager reportManager;
    private final TsiAlarmManager alarmManager;
    private final TsiTpmsManager tpmsManager;
    private final TsiDatabaseService tsiDatabaseService;
    private final KafkaProducerService kafkaProducerService;
    private final KafkaConsumerService kafkaConsumerService;

    @Async
    @Scheduled(cron = "* * * * * *")  // 1초 주기 작업 실행
    public void staticsForPacketSecond() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.tpmsManager.resetSecond(this.config.getServerId());
        log.info("{}", String.format("%25s: %s", "staticsForPacketSecond", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

    @Async
    @Scheduled(cron = "0/5 * * * * *")  // 5초 주기 작업 실행
    public void checkKafkaServerAlive() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.kafkaConsumerService.start();
        this.kafkaProducerService.sendPing();
        log.info("{}", String.format("%25s: %s", "checkKafkaServerAlive", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

    @Async
    @Scheduled(cron = "0/5 * * * * *")  // 5초 주기 작업 실행
    public void checkSessionTimeout() {
        if (!this.config.isStartup()) {
            return;
        }
        if (!this.alarmManager.checkAlarm(TsiAlarmConfigVo.COMM_02)) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        long timeout = 0;
        TsiAlarmConfigVo vo = this.alarmManager.get(TsiAlarmConfigVo.COMM_02);
        if (vo == null) return; // 이거면 안됌.
        timeout = vo.getValue() * 1000L;
//        timeout *= 3; // 3배로 늘려서 체크
        if (timeout <= 0) {
            log.error("checkSessionTimeout: timeout value error: {}", timeout);
            return;
        }
        this.reportManager.checkSessionTimeout(timeout);
        log.info("{}", String.format("%25s: %s", "checkSessionTimeout", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

    @Async
    @Scheduled(cron = "0/30 * * * * *")  // 30초 주기 작업 실행
    public void reportNodeSessionAlive() {
        if (!this.config.isStartup()) {
            return;
        }
        if (!this.trace.isSessionReport()) {
            return; // 세션 정보 보고 안함.
        }
        Elapsed elapsed = new Elapsed();
        this.reportManager.reportNodeSessions();
//        TsiSessionManager.getInstance().reportChannelSessions();
        log.info("{}", String.format("%25s: %s", "reportNodeSessionAlive", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

    @Async
    @Scheduled(cron = "5/35 * * * * *")  // 30초 주기 작업 실행
    public void reportQueueInformation() {
        if (!this.config.isStartup()) {
            return;
        }
        if (this.trace.isQueueReport()) {
            Elapsed elapsed = new Elapsed();
            this.reportManager.reportQueueInfo(false);
            log.info("{}", String.format("%25s: %s", "reportQueueInformation", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
        }
        else {
            this.reportManager.reportQueueInfo(true);
        }
    }

    @Async
    @Scheduled(cron = "0 * * * * *")  // 1분 주기 작업 실행
    public void staticsForPacketMinute() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.tpmsManager.resetMinute();
        log.info("{}", String.format("%25s: %s", "staticsForPacketMinute", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

    @Async
    @Scheduled(cron = "0/10 * * * * *")  // 1분 주기 작업 실행
    public void loadCommDump() {
        if (!this.config.isStartup()) {
            return;
        }
        this.trace.loadTraceInfo();
    }

    @Async
    @Scheduled(cron = "0 0 0 * * *")  // 1일 주기 작업 실행
    public void staticsForPacketDay() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.tpmsManager.resetDay();
        log.info("{}", String.format("%25s: %s", "staticsForPacketDay", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

    @Async
    @Scheduled(cron = "0 * * * * *")  // 1분 주기 작업 실행
    public void loadBaseDatabase() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.tsiDatabaseService.loadDatabase();
        this.tsiDatabaseService.updateProcessState(1);
        log.info("{}", String.format("%25s: %s", "loadBaseDatabase", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

}
