package com.utic.center.utic.traf.server.controller;

import com.utic.center.common.utils.LogUtils;
import com.utic.center.common.utils.TimeUtils;
import com.utic.center.utic.traf.server.dto.BatchJobInfoDto;
import com.utic.center.utic.traf.server.dto.TrafPrcsTimeDto;
import com.utic.center.utic.traf.server.repository.ApplicationRepository;
import com.utic.center.utic.traf.server.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;

import java.time.LocalDateTime;

@Slf4j
@Controller
@RequiredArgsConstructor
public class UticTrafServerController {

    private final LinkService linkService;
    private final LinkTrafPrcsPrepareService prepareService;
    private final LinkTrafPrcsAfterService prcsAfterService;

    private final LinkTrafAsnService asnService;


    private final LinkTrafCollectService collectService;
    private final LinkTrafFusionService fusionService;
    private final LinkTrafMissingService missingService;
    private final LinkTrafSaveUticService saveUticService;
    private final LinkTrafSaveDwdbService saveDwdbService;
    private final LinkTrafPrcsDebugService debugService;

    private String prevPrcsTime = "";
    private boolean isRunning = false;
    private int minute = -1;

    private void calculateTime() {
        LocalDateTime now = LocalDateTime.now();
        this.minute = now.getMinute();  // 현재 분
    }

    private void initialize() {
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int month = now.getMonthValue();
        int day = now.getDayOfMonth();
        int hour = now.getHour();
        int minute = now.getMinute();
        int second = now.getSecond();
        String nowTime = String.format("%04d%02d%02d%02d%02d%02d", year, month, day, hour, minute, second);
        String prcsTime = String.format("%04d%02d%02d%02d%02d00", year, month, day, hour, minute);

        TrafPrcsTimeDto result = TrafPrcsTimeDto.builder()
                .currTime(nowTime)
                .prcsTime(prcsTime)
                .quarterTime(TimeUtils.addMinutes(prcsTime, 15))
                .past05MinTime(TimeUtils.addMinutes(prcsTime, -5))
                .past10MinTime(TimeUtils.addMinutes(prcsTime, -10))
                .incdTime(TimeUtils.addMinutes(prcsTime, -720))
                .build();
        ApplicationRepository.setTrafPrcsTime(result);
        this.linkService.getFusionInfo().init(prcsTime);
    }
    public void run() {
        final String header = "==========================================================================================================";
        final String completed = "**********************************************************************************************************";
        final long start = System.currentTimeMillis();
        long tmpStart;
        calculateTime();
        if (this.minute % 5 != 0) { // 5분마다 실행
            this.prcsAfterService.processing();
            return;
        }

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

        this.isRunning = true; // 현재 작업이 실행중임을 표시
        this.prevPrcsTime = TimeUtils.getCurrentTimeString(); // 현재 작업 시간 저장

        log.info("##>> 05MIN {}: [{}]", LogUtils.elapsedLogLength("정주기 교통정보 가공 Start", 5), this.prevPrcsTime);

        BatchJobInfoDto jobInfo = new BatchJobInfoDto(TimeUtils.now());

        try {
            // 0. 가공 초기화 작업
            initialize();

            // 1. ASN 교통정보 이관(TRAFFIC_LOC) 작업
            this.asnService.processing();
            jobInfo.setAsnEtlpTime(System.currentTimeMillis() - start);

            // 2. 수집원별 링크 원시 교통정보 조회
            tmpStart = System.currentTimeMillis();
            this.collectService.processing();
            jobInfo.setCollectTime(System.currentTimeMillis() - tmpStart);

            // 2. 가공방식에 따른 퓨전 소통정보 생성
            tmpStart = System.currentTimeMillis();
            this.fusionService.processing();
            jobInfo.setFusionTime(System.currentTimeMillis() - tmpStart);

            // 3. 결측처리
            tmpStart = System.currentTimeMillis();
            this.missingService.processing();
            jobInfo.setMissingTime(System.currentTimeMillis() - tmpStart);

            // 4. 소통정보 저장(TRAFFIC_CENTER_CACHE) 작업
            tmpStart = System.currentTimeMillis();
            this.saveUticService.processing();
            jobInfo.setSaveCenterTime(System.currentTimeMillis() - tmpStart);
            jobInfo.setSaveTrafficTime(System.currentTimeMillis() - start);
            log.info("##>> 05MIN {}", LogUtils.elapsedLogLength("정주기 교통정보 저장 완료", jobInfo.getSaveTrafficTime(), 5));
            log.info(completed);

            // 5. DWDB 저장
            tmpStart = System.currentTimeMillis();
            this.saveDwdbService.processing();
            jobInfo.setSaveDwdbTime(System.currentTimeMillis() - tmpStart);

            // 6. 디버그 정보 출력
            this.debugService.processing();

            // 7. 가공 기초정보 로딩 및 가공 후 처리
            tmpStart = System.currentTimeMillis();
            this.prepareService.processing();
            jobInfo.setPrepareTime(System.currentTimeMillis() - tmpStart);

            // 8. 가공 후 처리
            tmpStart = System.currentTimeMillis();
            this.prcsAfterService.processing();
            jobInfo.setPrcsAfterTime(System.currentTimeMillis() - tmpStart);
        }
        finally {
            this.isRunning = false; // 현재 작업이 종료됨을 표시
        }

        // 작업 정보를 리스트에 저장(http://localhost:9871/info)
        long executionTime = System.currentTimeMillis() - start;
        jobInfo.setEndTime(TimeUtils.now());
        jobInfo.setElapsedTime(executionTime);
        ApplicationRepository.addJobInfo(jobInfo);

        log.info("<<## 05MIN {} [{}].", LogUtils.elapsedLogLength("정주기 교통정보 가공 End", executionTime, 5), this.prevPrcsTime);
        log.info(header);
    }
}
