package incheon.ags.mrb.analysis.service.impl;

import incheon.ags.mrb.analysis.domain.AnalysisKind;
import incheon.ags.mrb.analysis.domain.AnalysisStatus;
import incheon.ags.mrb.analysis.mapper.AnalysisHistoryMapper;
import incheon.ags.mrb.analysis.service.AnalysisHistoryService;
import incheon.ags.mrb.analysis.vo.AnlsHstryDtlVO;
import incheon.ags.mrb.analysis.vo.AnlsHstryJoinVO;
import incheon.ags.mrb.analysis.vo.AnlsHstryVO;
import incheon.com.security.vo.LoginVO;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class AnalysisHistoryServiceImpl implements AnalysisHistoryService {

    private static final Logger logger = LoggerFactory.getLogger(AnalysisHistoryServiceImpl.class);

    private final AnalysisHistoryMapper mapper;
    /**
     * 공간 분석 이력을 DB에 등록한다.
     *
     * @param analysisKind 분석 종류
     * @return 생성된 이력 VO (ID 포함)
     */
    public AnlsHstryVO insertAnlsHstry(AnalysisKind analysisKind) {
        AnlsHstryVO anlsHstryVO = new AnlsHstryVO();
        anlsHstryVO.setUserId(getCurrentUserId());
        anlsHstryVO.setAnlsKnd(analysisKind);
        anlsHstryVO.setAnlsStcd(AnalysisStatus.PENDING);
        anlsHstryVO.setDmndTm(LocalDateTime.now());
        mapper.insertHstry(anlsHstryVO);
        return anlsHstryVO;
    }


    /**
     * 서버가 비정상적으로 종료된 후 재기동될 때, 아직 완료되지 않은 분석 작업의 상태를 초기화합니다.
     */
    @PostConstruct
    @Profile("prod")
    public void resetIncompleteAnalyses(){
//        mapper.markPendingOrRunningAsFailed();
    }

    /**
     * 공간 분석 이력 상태를 갱신한다.
     *
     * @param anlsHstryId    분석 이력 ID
     * @param analysisStatus 변경할 상태 코드
     * @param anlsSttsMssage 상태 메시지 (에러 메시지 등)
     */
    public void updateAnlsHstry(int anlsHstryId, AnalysisStatus analysisStatus, String anlsSttsMssage, Integer userLyrId, String userId) {
        AnlsHstryVO anlsHstryVO = new AnlsHstryVO();
        anlsHstryVO.setAnlsHstryId(anlsHstryId);
        anlsHstryVO.setUserId(userId);
        anlsHstryVO.setAnlsStcd(analysisStatus);
        anlsHstryVO.setAnlsSttsMssage(anlsSttsMssage);
        if (analysisStatus.equals(AnalysisStatus.SUCCESS) || analysisStatus.equals(AnalysisStatus.FAILED)) {
            anlsHstryVO.setCmptnTm(LocalDateTime.now());
        }
        if (userLyrId != null) {
            anlsHstryVO.setUserLyrId(userLyrId);
        }
        mapper.updateHstry(anlsHstryVO);
    }

    /**
     * 공간 분석 이력 상세를 DB에 등록한다.
     *
     * @param anlsHstryId 분석 이력 ID
     * @param sourcLyrNm  분석 소스 레이어명
     * @param bndryLyrNm  경계 레이어명
     * @param optionJson  분석 옵션 JSON 문자열
     */
    public void insertAnlsHstryDtl(int anlsHstryId, String sourcLyrNm, String bndryLyrNm, String optionJson) {
        AnlsHstryDtlVO anlsHstryDtlVO = new AnlsHstryDtlVO();
        anlsHstryDtlVO.setAnlsHstryId(anlsHstryId);
        anlsHstryDtlVO.setAnlsSourcLyrNm(sourcLyrNm);
        anlsHstryDtlVO.setAnlsPption(optionJson);
        if (bndryLyrNm != null) {
            anlsHstryDtlVO.setAnlsBndryLyrNm(bndryLyrNm);
        }
        mapper.insertHstryDtl(anlsHstryDtlVO);
    }

    /**
     * 현재 로그인된 사용자 ID를 조회한다.
     *
     * @return 사용자 ID, 없으면 null
     */
    private String getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof LoginVO loginVO) {
            return loginVO.getUserId();
        }
        return null;
    }

    @Override
    public List<AnlsHstryJoinVO> getAnalysisHistory(String userId, int offset, int limit, String analysisType, String status, String sortOrder) {
        logger.info("조회 대상 userId: {}, analysisType: {}, status: {}, sortOrder: {}", userId, analysisType, status, sortOrder);

        String safeSortOrder = "DESC";
        if ("ASC".equalsIgnoreCase(sortOrder)) {
            safeSortOrder = "ASC";
        }

        // 페이징 데이터 조회
        List<AnlsHstryJoinVO> historyList = mapper.selectMyHstryWithDtl(
            userId,
            offset,
            limit,
            analysisType,
            status,
            safeSortOrder
        );

        if (historyList == null) {
            historyList = new ArrayList<>();
        }

        logger.info("조회된 이력 개수: {}", historyList.size());

        return historyList;
    }

    @Override
    public int getAnalysisHistoryCount(String userId, String analysisType, String status) {
        int totalCount = mapper.countMyHstry(userId, analysisType, status);
        logger.info("필터 적용 후 전체 개수: {}", totalCount);
        return totalCount;
    }

    @Override
    public void deleteAnalysisHistory(String userId, int historyId) {
        logger.info("삭제 요청 - userId: {}, historyId: {}", userId, historyId);
        
        // 상세 삭제
        mapper.deleteHstryDtl(historyId);
        
        // 이력 삭제
        int deletedCount = mapper.deleteHstry(historyId);

        if (deletedCount == 0) {
            throw new IllegalArgumentException("이력을 찾을 수 없습니다.");
        }

        logger.info("분석이력 삭제 완료 - historyId: {}", historyId);
    }

    /**
     * 분석 이력 테이블에서 아직 완료되지 않은 작업을 실패 상태로 변경합니다.
     * - PENDING(대기) 또는 RUNNING(진행 중) 상태의 분석 작업을 실패(FAILED) 상태로 마킹
     * - 서버가 비정상 종료되었거나, 이전 실행에서 완료되지 않은 작업을 정리
     */
    @Override
    public void markPendingOrRunningAsFailed() {
        mapper.markPendingOrRunningAsFailed();
    }
}
