package com.tsi.comm.server.scheduler;

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.service.TsiCommServerService;
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 com.tsi.comm.server.xnet.NetUtils;
import com.tsi.common.utils.Elapsed;
import com.tsi.common.utils.TimeUtils;
import lombok.RequiredArgsConstructor;
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;

import javax.annotation.PostConstruct;

@Slf4j
@RequiredArgsConstructor
@EnableScheduling
@Component
public class ApplicationScheduler {

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

    private String hostName;

    @PostConstruct
    void init() {
        this.hostName = NetUtils.getHostName();
    }

    @Scheduled(cron = "0/5 * * * * *")  //
    public void staticsForPacketSecond() {
        if (!this.config.isStartup()) {
            return;
        }
//        Elapsed elapsed = new Elapsed();
        this.tpmsManager.resetSecond(this.config.getServerId(), this.hostName);
//        log.info("{}", String.format("%25s: %s", "staticsForPacketSecond", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
    }

    @Scheduled(cron = "0/5 * * * * *")  //
    public void checkKafkaServerAlive() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.kafkaConsumerService.start();
        this.kafkaProducerService.sendPing();
        if (elapsed.milliSeconds() > 500) {
            log.info("{}", String.format("%25s: %s", "checkKafkaServerAlive", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
        }
    }

//    @Scheduled(cron = "0/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())));
//    }

    @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())));
    }

    @Scheduled(cron = "5/35 * * * * *")  //
    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);
        }
    }

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

    @Scheduled(cron = "10 * * * * *")  //
    public void loadTraceInfo() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.trace.loadTraceInfo();
        if (elapsed.milliSeconds() > 500) {
            log.info("{}", String.format("%25s: %s", "loadTraceInfo", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
        }
    }

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

    @Scheduled(cron = "0 0/5 * * * *")  //
    public void loadBaseDatabase() {
        if (!this.config.isStartup()) {
            return;
        }
        Elapsed elapsed = new Elapsed();
        this.tsiCommServerService.loadDatabase();
        this.tsiCommServerService.updateProcessState(1);
        if (elapsed.milliSeconds() > 500) {
            log.info("{}", String.format("%25s: %s", "loadBaseDatabase", TimeUtils.elapsedTimeStr(elapsed.nanoSeconds())));
        }
    }

}
