package incheon.ags.dss.decline.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import incheon.ags.dss.decline.service.PredictServce;
import incheon.ags.dss.decline.vo.AnaPredictScaVO;
import incheon.ags.dss.regen.service.AnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import incheon.ags.dss.decline.service.AnaZoneDgnsDtlService;
import incheon.ags.dss.decline.mapper.AnaZoneDgnsDtlMapper;
import incheon.ags.dss.decline.vo.AnaZoneDgnsDtlVO;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Service("anaZoneDgnsDtlService")
@RequiredArgsConstructor
@Slf4j
public class AnaZoneDgnsDtlServiceImpl implements AnaZoneDgnsDtlService {

    @Autowired
    @Lazy
    private PredictServce predictServce;

    private final AnaZoneDgnsDtlMapper mapper;

    @Override
    @Transactional
    public synchronized String runDiagnosisAnalysis(AnaZoneDgnsDtlVO vo) throws Exception {
        // 1. [신규] 동일한 조건의 기존 진단 이력이 있는지 확인
        String existingDgnsNo = mapper.selectExistingDiagnosisNo(vo);

        if (existingDgnsNo != null) {
            // 1-1. 결과 데이터(ana_predict_sca)가 실제로 존재하는지도 더블 체크 (이력만 있고 데이터가 없을 수도 있음)
            int resultCount = mapper.selectPredictScaCount(existingDgnsNo);

            if (resultCount > 0) {
                log.info("Diagnosis already exists (dgnsNo: {}). Reuse result.", existingDgnsNo);
                return existingDgnsNo; // 기존 번호 반환 (재분석 건너뜀)
            }

            // 데이터가 없으면(오류 등으로 중단된 건) 해당 이력 삭제 후 재실행 로직으로 진행
            AnaZoneDgnsDtlVO delVO = new AnaZoneDgnsDtlVO();
            delVO.setDgnsNo(existingDgnsNo);
            mapper.deleteAnaZoneDgnsDtl(delVO);
        }

        // 2. 신규 등록 및 분석 실행 (기존 로직 유지)
        vo.setAnlsUnit("1");
        mapper.insertAnaZoneDgnsDtl(vo);
        String dgnsNo = vo.getDgnsNo();

        String crtrStr = vo.getCrtrPnttm();
        String predcStr = vo.getPredcPnttm();

        int baseYear = Integer.parseInt(crtrStr.length() >= 4 ? crtrStr.substring(0, 4) : crtrStr);
        int targetYear = Integer.parseInt(predcStr.length() >= 4 ? predcStr.substring(0, 4) : predcStr);

        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    predictServce.executeJavaPrediction(dgnsNo, vo.getZoneNo(), baseYear, targetYear, vo.getLOGIN_USER_ID());
                }
            });
        } else {
            predictServce.executeJavaPrediction(dgnsNo, vo.getZoneNo(), baseYear, targetYear, vo.getLOGIN_USER_ID());
        }

        return dgnsNo;
    }

    @Override
    // [신규] 폴링용 상태 체크 메서드
    public boolean checkDiagnosisCompletion(String dgnsNo) throws Exception {
        // 결과 테이블에 데이터가 들어왔는지 확인
        return mapper.selectPredictScaCount(dgnsNo) > 0;
    }
    
    @Override
    public String checkDiagnosisStatus(String dgnsNo) throws Exception {
        // 1. 진단 이력 상세 조회
        AnaZoneDgnsDtlVO searchVO = new AnaZoneDgnsDtlVO();
        searchVO.setDgnsNo(dgnsNo);
        AnaZoneDgnsDtlVO result = mapper.selectAnaZoneDgnsDtlDetail(searchVO);

        if (result == null) return "N"; // 데이터 없으면 진행중으로 간주

        // 2. 상태값(last_mdfcn_id) 확인 (우리가 PredictService에서 넣은 값)
        String dbFlag = result.getLastMdfcnId(); 

        if ("RUNNING".equals(dbFlag)) {
            return "N";    // 아직 도는 중 -> 프론트: 계속 Polling
        } 
        else if ("FAIL".equals(dbFlag)) {
            return "FAIL"; // 실패함 -> 프론트: 즉시 중단 및 에러 표시
        } 
        else if ("NO_DATA".equals(dbFlag)) {
            return "Y";    // 데이터 없음(정상 종료) -> 프론트: 완료
        }
        else {
            // SUCCESS 또는 사용자ID (정상 완료)
            return "Y";    // 성공 -> 프론트: 완료 및 결과 조회
        }
    }

    @Override
    public List<Map<String, Object>> selectDiagnosisResult(int dgnsNo, int targetYear) throws Exception {
        Map<String, Object> params = new HashMap<>();
        params.put("dgnsNo", dgnsNo);
        params.put("targetYear", targetYear);
        return mapper.selectDiagnosisResult(params);
    }

    @Override
    public List<AnaZoneDgnsDtlVO> selectAnaZoneDgnsDtlList(AnaZoneDgnsDtlVO vo) throws Exception {
        return mapper.selectAnaZoneDgnsDtlList(vo);
    }
    
    @Override
    public int selectAnaZoneDgnsDtlListCnt(AnaZoneDgnsDtlVO vo) throws Exception {
        return mapper.selectAnaZoneDgnsDtlListCnt(vo);
    }
    
    @Override
    public AnaZoneDgnsDtlVO selectAnaZoneDgnsDtlDetail(AnaZoneDgnsDtlVO vo) throws Exception {
        return mapper.selectAnaZoneDgnsDtlDetail(vo);
    }
    
    @Override
    public List<AnaZoneDgnsDtlVO> selectAnaZoneDgnsDtlRecentList(AnaZoneDgnsDtlVO vo) throws Exception {
        return mapper.selectAnaZoneDgnsDtlRecentList(vo);
    }
    
    @Override
    public void deleteAnaZoneDgnsDtl(AnaZoneDgnsDtlVO vo) throws Exception {
        mapper.deleteAnaZoneDgnsDtl(vo);
    }
    
    @Override
    public Map<String, Object> selectDiagnosisOptions() throws Exception {
        Map<String, Object> resultMap = new HashMap<>();

        // 1. 기준시점 (DB 조회)
        List<String> criterionYears = mapper.selectCriterionYears();
        resultMap.put("criterionYears", criterionYears);

        // 2. 예측시점 (로직 생성: 기준시점의 마지막 연도 ~ 10년 후)
        int baseYear = LocalDate.now().getYear();
        if (criterionYears != null && !criterionYears.isEmpty()) {
            int maxYear = Integer.MIN_VALUE;
            for (String yearStr : criterionYears) {
                if (yearStr == null) {
                    continue;
                }
                try {
                    int year = Integer.parseInt(yearStr.trim());
                    if (year > maxYear) {
                        maxYear = year;
                    }
                } catch (NumberFormatException ignored) {
                    // ignore non-numeric entries
                	// 숫자가 아닌 디렉토리는 건너뜀 (정상 동작)
                    log.trace("연도 파싱 실패(디렉토리 스킵): {}", yearStr);
                }
            }
            if (maxYear != Integer.MIN_VALUE) {
                baseYear = maxYear;
            }
        }
        List<Integer> predictionYears = new ArrayList<>();
        for (int i = 0; i <= 10; i++) {
            predictionYears.add(baseYear + i);
        }
        resultMap.put("predictionYears", predictionYears);

        return resultMap;
    }

}