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

import java.math.BigDecimal;
import java.util.*;

import incheon.ags.dss.config.mapper.SimZoneMstMapper;
import incheon.ags.dss.config.vo.SimZoneMstVO;
import incheon.ags.dss.status.service.StatAnalysisService;
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.status.service.AnaZoneStatService;
import incheon.ags.dss.status.service.AnaLgdFomService; // 범례 서비스
import incheon.ags.dss.status.vo.AnaLgdFomMstVO;
import incheon.ags.dss.status.vo.AnaLgdFomDtlVO; // 상세 VO
import incheon.com.cmm.context.RequestContext;
import incheon.ags.dss.status.mapper.AnaZoneStatMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Service("anaZoneStatService")
@RequiredArgsConstructor
@Slf4j
public class AnaZoneStatServiceImpl implements AnaZoneStatService {

    @Lazy
    @Autowired
    StatAnalysisService statAnalysisService;

    private final AnaZoneStatMapper mapper;
    private final AnaLgdFomService anaLgdFomService;

    // [추가] 구역 정보 조회를 위해 주입
    private final SimZoneMstMapper simZoneMstMapper;

    @Override
    @Transactional
    public synchronized Map<String, Object> runStatusAnalysis(int tareNo) throws Exception {
        // 1. [Check] 구역 정보 조회 (최종 수정일 확인용)
        SimZoneMstVO zoneSearchVO = new SimZoneMstVO();
        zoneSearchVO.setZoneNo((long)tareNo);
        SimZoneMstVO zoneInfo = simZoneMstMapper.selectSimZoneMstDetail(zoneSearchVO);

        if (zoneInfo == null) {
            throw new Exception("존재하지 않는 구역입니다.");
        }

        // 구역의 최종 수정 시점 (수정일이 없으면 등록일 기준)
        Date zoneModDate = zoneInfo.getLastMdfcnDt();
        if (zoneModDate == null) zoneModDate = zoneInfo.getFrstRegDt();

        // 2. [Check] 기존 분석 데이터의 최종 생성일 조회
        Date lastAnalysisDate = mapper.selectLastAnalysisDate(tareNo);

        // 3. [Decision] 재분석 여부 판단
        // 분석 데이터가 존재하고(AND), 분석 시점이 구역 수정 시점보다 같거나 늦다면(최신이라면)
        if (lastAnalysisDate != null && zoneModDate != null && !lastAnalysisDate.before(zoneModDate)) {
            log.info(">>> 구역(ZoneNo: {}) 변경 사항 없음. 기존 분석 데이터 재사용.", tareNo);
            log.info("    Zone Modified: {}, Last Analysis: {}", zoneModDate, lastAnalysisDate);

            // 재분석 없이 즉시 종료 (빈 맵 반환하여 성공 처리)
            return new HashMap<>();
        }

        // =========================================================
        // 여기부터는 실제 재분석 로직 (구역이 변경되었거나, 분석 데이터가 없는 경우)
        // =========================================================
        log.info(">>> 구역(ZoneNo: {}) 변경 감지 또는 데이터 없음. 재분석 수행.", tareNo);

        // 4. 기존 데이터 삭제
        mapper.deleteAnaZoneStatByTareNo(tareNo);

        // 5. 비동기 분석 실행
        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    triggerAsyncAnalysis(tareNo);
                }
            });
        } else {
            triggerAsyncAnalysis(tareNo);
        }

        return new HashMap<>();
    }

    // 비동기 실행 헬퍼 메서드
    private void triggerAsyncAnalysis(int tareNo) {
        String userId = RequestContext.getCurrentUserId();
        if (userId == null) userId = "ANONYMOUS";
        statAnalysisService.executeStatusAnalysisAsync(tareNo, userId);
    }
    
    @Override
    public List<Map<String, Object>> selectWeightValYearList() throws Exception {
        return mapper.selectWeightValYears(); // 파라미터 없음
    }

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

//    @Override
//    @Transactional
//    public List<Map<String, Object>> calculateAndGetMapStats(int tareNo, String crtrYr, String cmprYr, int lgdFrmNo) throws Exception {
//        String userId = RequestContext.getCurrentUserId();
//        
//        // 1. 통계 지도 마스터 등록
//        Map<String, Object> mstParams = new HashMap<>();
//        mstParams.put("tareNo", tareNo);
//        mstParams.put("lgdFrmNo", lgdFrmNo); // 프론트에서 받은 범례 ID 사용
//        mstParams.put("userId", userId);
//        mstParams.put("crtrYr", crtrYr);     // 프론트에서 받은 기준년도
//        mstParams.put("cmprYr", cmprYr);     // 프론트에서 받은 비교년도
//        
//        int stngNo = mapper.insertAnaStatsMapMst(mstParams);
//
//        // 2. 상세 적재
//        Map<String, Object> dtlParams = new HashMap<>();
//        dtlParams.put("stngNo", stngNo);
//        dtlParams.put("tareNo", tareNo);
//        dtlParams.put("userId", userId);
//        mapper.insertAnaStatsMapDtl(dtlParams);
//
//        // 3. 결과 조회
//        Map<String, Object> resParams = new HashMap<>();
//        resParams.put("stngNo", stngNo);
//        return mapper.selectMapIndicatorResult(resParams);
//    }

    @Override
    public List<Map<String, Object>> selectAnalyzedYearList(int tareNo) throws Exception {
        Map<String, Object> params = new HashMap<>();
        params.put("tareNo", tareNo);
        
        // Mapper의 기존 쿼리 재사용
        return mapper.selectAnalyzedYears(params);
    }
    
    /**
     * [통합 로직] 지표 분석 및 지도 데이터 생성
     * 1. 통계 지도 설정 저장 (MST)
     * 2. 지표값 계산 및 적재 (DTL)
     * 3. Gap 분석 결과 조회 (SELECT)
     */
    @Override
    @Transactional
    public Map<String, Object> processIndicatorAnalysis(Map<String, Object> params) throws Exception {
        String userId = RequestContext.getCurrentUserId();
        
        // 2. [Null 처리] 비로그인(Postman 등) 상태면 'admin'으로 대체
        if (userId == null || userId.isEmpty()) {
            userId = "ANONYMOUS"; // DB에 존재하는 유효한 ID여야 함
            log.warn("User ID not found in session. Using default: {}", userId);
        }
        
        params.put("userId", userId);

        // 1. 통계 지도 마스터 등록 (MST) -> stngNo 생성
        // 파라미터: tareNo, lgdFrmNo, crtrYr, cmprYr
        mapper.insertAnaStatsMapMst(params); 
        
        log.warn("processIndicatorAnalysis params: {}", params);
        
        // mapper xml의 selectKey나 useGeneratedKeys로 params에 'stngNo'가 담겨야 함. 
        // 만약 리턴값으로 받는다면: int stngNo = mapper.insertAnaStatsMapMst(params); params.put("stngNo", stngNo);

        // 2. 통계 지도 상세 적재 (DTL) - 해당 설정의 지표값 계산 저장
        // 파라미터: stngNo, tareNo
        mapper.insertAnaStatsMapDtl(params);

        // 3. Gap 분석 조회 (SELECT)
        // 파라미터: tareNo, baye(crtrYr), idctId
        // Mapper 쿼리에서 #{baye}를 쓰므로 키 이름 맞춰줌
        params.put("baye", params.get("crtrYr")); 
        
        List<Map<String, Object>> gapList = mapper.selectGapAnalysis(params);

        // 4. 결과 리턴 (설정번호 + Gap분석결과)
        Map<String, Object> result = new HashMap<>();
        result.put("stngNo", params.get("stngNo")); // 지도 레이어 ID로 활용 가능
        result.put("gapList", gapList);

        return result;
    }
    
    @Override
    public List<Map<String, Object>> selectGapAnalysis(int tareNo, String baye, String idctId) throws Exception {
        Map<String, Object> params = new HashMap<>();
        params.put("tareNo", tareNo);
        params.put("baye", baye);
        params.put("idctId", idctId);
        return mapper.selectGapAnalysis(params);
    }

    @Override
    public List<Map<String, Object>> selectGapAnalysisAll(int tareNo, String baye) throws Exception {
        Map<String, Object> params = new HashMap<>();
        params.put("tareNo", tareNo);
        params.put("baye", baye);
        
        String userId = RequestContext.getCurrentUserId();
        if (userId == null) userId = "ANONYMOUS";
        params.put("userId", userId);
        
        return mapper.selectGapAnalysisAll(params);
    }

    // [신규] 상태 확인용
    @Override
    public boolean checkStatusCompletion(int tareNo) throws Exception {
        // insertCalculatedZoneStat이 수행되면 데이터가 쌓임
        return mapper.selectZoneStatCount(tareNo) > 0;
    }
}