package com.its.vds.stat.server.controller;

import com.its.vds.stat.server.service.VdsStatServerService;
import com.its.vds.stat.server.utils.LogUtils;
import com.its.vds.stat.server.utils.StatisticsTime;
import com.its.vds.stat.server.utils.TimeUtils;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;

@Slf4j
@Controller
@RequiredArgsConstructor
public class VdsStatServerController {

    private final MeterRegistry meterRegistry;
    private final VdsStatServerRestController restController;
    private final VdsStatServerService service;

    private final StatisticsTime its = new StatisticsTime();
    private boolean is05Min = false;
    private String prevPrcsTime;

    private Timer min05Timer;
    private Counter min05Counter;
    private Timer min15Timer;
    private Counter min15Counter;
    private Timer hourTimer;
    private Counter hourCounter;
    private Timer monthTimer;
    private Counter dayCounter;
    private Timer dayTimer;
    private Counter monthCounter;
    private Timer yearTimer;
    private Counter yearCounter;

    @PostConstruct
    void init() {
        this.min05Timer = Timer.builder("vds_stat_05min_execution_time")
                .description("Execution time for 5min VDS stats")
                .register(this.meterRegistry);
        this.min05Counter = Counter.builder("vds_stat_05min_count")
                .description("Processed records for 5min VDS stats")
                .register(this.meterRegistry);
        this.min15Timer = Timer.builder("vds_stat_15min_execution_time")
                .description("Execution time for 15min VDS stats")
                .register(this.meterRegistry);
        this.min15Counter = Counter.builder("vds_stat_15min_count")
                .description("Processed records for 15min VDS stats")
                .register(this.meterRegistry);
        this.hourTimer = Timer.builder("vds_stat_hour_execution_time")
                .description("Execution time for hour VDS stats")
                .register(this.meterRegistry);
        this.hourCounter = Counter.builder("vds_stat_hour_count")
                .description("Processed records for hour VDS stats")
                .register(this.meterRegistry);
        this.dayTimer = Timer.builder("vds_stat_day_execution_time")
                .description("Execution time for day VDS stats")
                .register(this.meterRegistry);
        this.dayCounter = Counter.builder("vds_stat_day_count")
                .description("Processed records for day VDS stats")
                .register(this.meterRegistry);
        this.monthTimer = Timer.builder("vds_stat_month_execution_time")
                .description("Execution time for month VDS stats")
                .register(this.meterRegistry);
        this.monthCounter = Counter.builder("vds_stat_month_count")
                .description("Processed records for month VDS stats")
                .register(this.meterRegistry);
        this.yearTimer = Timer.builder("vds_stat_year_execution_time")
                .description("Execution time for year VDS stats")
                .register(this.meterRegistry);
        this.yearCounter = Counter.builder("vds_stat_year_count")
                .description("Processed records for year VDS stats")
                .register(this.meterRegistry);
    }

    private void calculateTime() {
        LocalDateTime now = LocalDateTime.now();
        int minute = now.getMinute();   // 현재 분
        this.is05Min = (minute % 5 == 0);           // 5분마다 실행
    }

    public boolean run() {
        final String header = "==========================================================================================================";
        final String step = "----------------------------------------------------------------------------------------------------------";
        final String completed = "**********************************************************************************************************";
        final long start = System.currentTimeMillis();

        calculateTime();

        if (!this.is05Min) { // 5분마다 실행
            return false;
        }

        log.info(header);
        if (this.its.IsProcessing()) {
            log.warn("[WAN] {}: [{}] - Already running.", LogUtils.elapsedLog("Overlapping"), this.prevPrcsTime);
        }

        this.prevPrcsTime = TimeUtils.getCurrentTimeString(); // 현재 작업 시간 저장
        this.its.init();
        this.its.setProcessing(true);

//        log.info("5분 통계: curr: {}, 5min: {}, from: {}, to: {}", TimeUtils.getCurrentTimeString(), its.getPrcsFiveMin(), its.getPrcsFiveMinFrom(), its.getPrcsFiveMinTo());
//        log.info("15분 통계: curr: {}, 5min: {}, from: {}, to: {}", TimeUtils.getCurrentTimeString(), its.getStat15MinFrom(), its.getStat15MinFrom(), its.getStat15MinTo());
//        log.info("1시간 통계: curr: {}, 5min: {}, from: {}, to: {}", TimeUtils.getCurrentTimeString(), its.getStatHourTime(), its.getStatHourTime(), its.getStatHourTo());
//        log.info("일 통계: curr: {}, 5min: {}, from: {}, to: {}", TimeUtils.getCurrentTimeString(), its.getStatDayFrom(), its.getStatDayFrom(), its.getStatDayTo());
//        String STAT_DT1 = its.getStatMonFrom().substring(0, 6) + "00000000";
//        log.info("월 통계: curr: {}, 5min: {}, from: {}, to: {}", TimeUtils.getCurrentTimeString(), STAT_DT1, its.getStatMonFrom(), its.getStatMonTo());
//        String statYear1 = its.getStatYearFrom().substring(0, 4) + "0000000000";
//        log.info("연 통계: curr: {}, 5min: {}, from: {}, to: {}", TimeUtils.getCurrentTimeString(), statYear1, its.getStatYearFrom(), its.getStatYearTo());

        int result;
        Integer recordResult;
        if (this.is05Min) {
            // VDS 검지기 5분 가공
            recordResult = this.min05Timer.record(() ->
                 this.service.crtVdsDtctHs(this.its.getPrcsFiveMin(), this.its.getPrcsFiveMinFrom(), this.its.getPrcsFiveMinTo())
            );
            result = recordResult != null ? recordResult : -1;
            this.min05Counter.increment(result);
//            result = this.service.crtVdsDtctHs(this.its.getPrcsFiveMin(), this.its.getPrcsFiveMinFrom(), this.its.getPrcsFiveMinTo());
            this.restController.addMin05Hs(this.prevPrcsTime, this.its.getPrcsFiveMin(), this.its.getPrcsFiveMinFrom(), this.its.getPrcsFiveMinTo(), result);
            log.info("crtVdsDtctHs: {} EA.", result);
            log.info(step);
        }

        log.info("##>> 05MIN {}: [{}]", LogUtils.elapsedLogLength("정주기 VDS 통계 Start", 5), this.prevPrcsTime);
        if (this.its.isStat15Min()) {
            // 5분 정주기 가공이 끝나고 15분 주기일 경우(00, 15, 30, 45 분 일경우 15분 통계 정보를 생성한다)
            recordResult = this.min15Timer.record(() ->
                    this.service.crtVdsDtct15MinStat(this.its.getStat15MinFrom(), this.its.getStat15MinFrom(), this.its.getStat15MinTo())
            );
            result = recordResult != null ? recordResult : -1;
            this.min15Counter.increment(result);
//            result = this.service.crtVdsDtct15MinStat(this.its.getStat15MinFrom(), this.its.getStat15MinFrom(), this.its.getStat15MinTo());
            this.restController.addMin15Hs(this.prevPrcsTime, this.its.getStat15MinFrom(), this.its.getStat15MinFrom(), this.its.getStat15MinTo(), result);
            log.info("crtVdsDtct15MinStat: {} EA.", result);
            log.info(step);
        }

        if (this.its.isStatHour()) {
            // 매시 5분 가공완료후 1시간 통계
            recordResult = this.hourTimer.record(() ->
                    this.service.crtVdsDtctHhStat(this.its.getStatHourTime(), this.its.getStatHourTime(), this.its.getStatHourTo())
            );
            result = recordResult != null ? recordResult : -1;
            this.hourCounter.increment(result);
//            result = this.service.crtVdsDtctHhStat(this.its.getStatHourTime(), this.its.getStatHourTime(), this.its.getStatHourTo());
            this.restController.addHourHs(this.prevPrcsTime, this.its.getStatHourTime(), this.its.getStatHourTime(), this.its.getStatHourTo(), result);
            log.info("crtVdsDtctHhStat: {} EA.", result);
            log.info(step);
        }

        if (this.its.isStatDay()) {
            // 00시 10분 가공이 끝나면 이전일의 통계 정보를 가공.
            recordResult = this.dayTimer.record(() ->
                    this.service.crtVdsDtctDdStat(this.its.getStatDayFrom(), this.its.getStatDayFrom(), this.its.getStatDayTo())
            );
            result = recordResult != null ? recordResult : -1;
            this.dayCounter.increment(result);
//            result = this.service.crtVdsDtctDdStat(this.its.getStatDayFrom(), this.its.getStatDayFrom(), this.its.getStatDayTo());
            this.restController.addDayHs(this.prevPrcsTime, this.its.getStatDayFrom(), this.its.getStatDayFrom(), this.its.getStatDayTo(), result);
            log.info("crtVdsDtctDdStat: {} EA.", result);
            log.info(step);
        }

        if (this.its.isStatMon()) {
            //  02시 10분 가공이 끝나면 이전일의 월통계 정보를 누적 가공.
            String statMon = this.its.getStatMonFrom().substring(0, 6) + "00000000";
            recordResult = this.monthTimer.record(() ->
                    this.service.crtVdsDtctMnStat(statMon, this.its.getStatMonFrom(), this.its.getStatMonTo())
            );
            result = recordResult != null ? recordResult : -1;
            this.monthCounter.increment(result);
//            result = this.service.crtVdsDtctMnStat(statMon, this.its.getStatMonFrom(), this.its.getStatMonTo());
            this.restController.addMonthHs(this.prevPrcsTime, statMon, this.its.getStatMonFrom(), this.its.getStatMonTo(), result);
            log.info("crtVdsDtctMnStat: {} EA.", result);
            log.info(step);
        }
        if (this.its.isStatYear()) {
            // 02시 35분 가공이 끝나면 이전일의 연통계 정보를 누적 가공.
            String statYear = its.getStatYearFrom().substring(0, 4) + "0000000000";
            recordResult = this.yearTimer.record(() ->
                    this.service.crtVdsDtctYyStat(statYear, this.its.getStatYearFrom(), this.its.getStatYearTo())
            );
            result = recordResult != null ? recordResult : -1;
            this.yearCounter.increment(result);
//            result = this.service.crtVdsDtctYyStat(statYear, this.its.getStatYearFrom(), this.its.getStatYearTo());
            this.restController.addYearHs(this.prevPrcsTime, statYear, this.its.getStatYearFrom(), this.its.getStatYearTo(), result);
            log.info("crtVdsDtctYyStat: {} EA.", result);
            log.info(step);
        }

        this.its.setProcessing(false);
        long executionTime = System.currentTimeMillis() - start;
        log.info("<<## 05MIN {} [{}].", LogUtils.elapsedLogLength("정주기 VDS 통계 End", executionTime, 5), this.prevPrcsTime);
        log.info(completed);
        return true;
    }
}
