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

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

import incheon.ags.dss.regen.service.AnalysisService;
import incheon.ags.dss.regen.service.UrbTrgtClsfService;
import incheon.ags.dss.regen.vo.UrbTrgtClsfMstVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import incheon.ags.dss.regen.service.UrbFcltyAnlsService;
import incheon.ags.dss.regen.mapper.UrbFcltyAnlsMapper;
import incheon.ags.dss.regen.vo.UrbFcltyAnlsMstVO;
import incheon.ags.dss.regen.vo.UrbFcltyAnlsDtlVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Service("urbFcltyAnlsService")
@RequiredArgsConstructor
@Slf4j
public class UrbFcltyAnlsServiceImpl implements UrbFcltyAnlsService {

    private final UrbFcltyAnlsMapper mapper;

    @Autowired
    @Lazy
    private AnalysisService analysisService;

    @Autowired
    @Lazy
    private UrbTrgtClsfService urbTrgtClsfService;

	// [시나리오 2] 사전 분류 생성 (Access Analysis용)
    @Override
    @Transactional
    public int createTargetClassification(UrbFcltyAnlsMstVO vo) throws Exception {
        // VO 변환 (AnlsMstVO -> TrgtClsfMstVO)
        UrbTrgtClsfMstVO trgtVO = new UrbTrgtClsfMstVO();
        trgtVO.setRadu(vo.getRadu());
        trgtVO.setZoneNo(vo.getZoneNo());
        trgtVO.setMdlAtrbCd(vo.getMainUsgCd());
        trgtVO.setTrgtClsfNm("사용자지정_" + System.currentTimeMillis());
        trgtVO.setUserDsgnYn("Y"); // 사용자가 명시적 생성
        trgtVO.setFrstRegId(vo.getUserId());
        trgtVO.setLastMdfcnId(vo.getUserId());

        // Java 로직 호출
        return urbTrgtClsfService.createTargetClassificationInJava(trgtVO);
    }
    
    @Override
    @Transactional
    public int runFacilityAnalysis(UrbFcltyAnlsMstVO vo) throws Exception {
        // 1. [Check] 분석 대상 시설물이 존재하는지 확인
        int targetCount = mapper.countFacilitiesInSearchArea(vo);
        if (targetCount == 0) {
            throw new Exception("설정된 반경 내에 분석 대상 시설물이 존재하지 않습니다.");
        }

        // 2. [Check] 재활용 가능한 기존 분석 결과 확인
        // (구역이 수정되지 않았고, 동일 조건의 분석이 있다면 재사용)
        Integer existingAnlsNo = mapper.selectValidLatestAnalysis(vo);

        if (existingAnlsNo != null) {
            log.info("Reuse Valid Facility Analysis Result (AnlsNo: {})", existingAnlsNo);
            // 재분석 없이 기존 번호 리턴 -> 프론트에서는 바로 결과 조회
            return existingAnlsNo;
        }

        // 3. [New] 신규 분석 실행 (기존 로직)
        log.info("Requesting New Facility Analysis (Async) for Zone: {}", vo.getZoneNo());

        vo.setPrcsCmptnYn("N");
        mapper.insertUrbFcltyAnlsMst(vo);

        int anlsNo = Integer.parseInt(vo.getFcltAnlsNo());

        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    analysisService.executeAnalysisInJava(anlsNo);
                }
            });
        } else {
            analysisService.executeAnalysisInJava(anlsNo);
        }

        return anlsNo;
    }
    
    @Override
    @Transactional
    public void completeAnalysisStatus(int fcltAnlsNo, String resultCode) throws Exception {
        Map<String, Object> param = new HashMap<>();
        param.put("fcltAnlsNo", fcltAnlsNo);
        param.put("resultCode", resultCode); // "SUCCESS" or "NO_DATA"
        
        mapper.updateAnalysisFinishFlag(param);
        log.info("Analysis Status Updated. Code: {} (No: {})", resultCode, fcltAnlsNo);
    }

    @Override
    public List<UrbFcltyAnlsMstVO> selectAnalysisList(UrbFcltyAnlsMstVO searchVO) throws Exception {
        return mapper.selectUrbFcltyAnlsMstList(searchVO);
    }

    @Override
    public int selectAnalysisListCnt(UrbFcltyAnlsMstVO searchVO) throws Exception {
        return mapper.selectUrbFcltyAnlsMstListCnt(searchVO);
    }

    @Override
    public List<UrbFcltyAnlsDtlVO> selectAnalysisResultList(UrbFcltyAnlsDtlVO searchVO) throws Exception {
        return mapper.selectUrbFcltyAnlsDtlList(searchVO);
    }
    
    @Override
    @Transactional
    public void deleteAnalysis(Integer fcltAnlsNo) throws Exception {
        // 상세 내역 먼저 삭제
        mapper.deleteUrbFcltyAnlsDtl(fcltAnlsNo);
        // 마스터 삭제
        mapper.deleteUrbFcltyAnlsMst(fcltAnlsNo);
    }

	@Override
	public int selectAnalysisResultListCnt(UrbFcltyAnlsDtlVO searchVO) throws Exception {
		return mapper.selectUrbFcltyAnlsDtlListCnt(searchVO);
	}

	@Override
	public void deleteResultItem(Integer rsltNo) throws Exception {
		mapper.deleteUrbFcltyAnlsDtlItem(rsltNo);
	}

    @Override
    public List<UrbFcltyAnlsMstVO> selectAceiAnlsMstList(UrbFcltyAnlsMstVO searchVO) throws Exception {
        return mapper.selectAceiAnlsMstList(searchVO);
    }

    @Override
    public UrbFcltyAnlsMstVO selectUrbFcltyAnlsMstDetail(int fcltAnlsNo) {
        return mapper.selectUrbFcltyAnlsMstDetail(fcltAnlsNo);
    }

    @Override
    public List<UrbFcltyAnlsDtlVO> selectTargetFacilities(UrbFcltyAnlsMstVO vo) throws Exception {
        return mapper.selectFacilitiesInSearchArea(vo);
    }
}
