package incheon.sgp.rst.service.impl;

import incheon.ags.ias.comCd.vo.ComCdVO;
import incheon.cmm.g2f.layer.mapper.G2FLayerMapper;
import incheon.cmm.g2f.layer.vo.TaskLayerSearchRequestDTO;
import incheon.cmm.g2f.layer.vo.TaskLayerVO;
import incheon.sgp.rst.mapper.RstComCdMapper;
import incheon.sgp.rst.service.RstTaskLyrTreeService;
import incheon.sgp.rst.vo.RstTaskLayerInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class RstTaskLyrTreeServiceImpl implements RstTaskLyrTreeService {

    private final G2FLayerMapper g2fLayerMapper;
    private final RstComCdMapper rstComCdMapper;

    @Override
    public List<ComCdVO> getRootLclsfList() {
        return rstComCdMapper.getRstRootComCdList();
    }

    @Override
    public List<RstTaskLayerInfoVO> getTaskLyrTreeInfo(String lclsfCd) {

        List<RstTaskLayerInfoVO> roots = new java.util.ArrayList<>();

        try {

            // 유효한 categoryId인지 검증
            if(!isValidCategory(lclsfCd)) {
                throw new IllegalArgumentException("등록되지 않은 카테고리입니다.");
            }

            // RST 레이어 조회 (lclsfCd = 01/02/03/04/05)
            List<ComCdVO> allCategories = rstComCdMapper.getRstComCdList(); //RST Cageory 조회
            TaskLayerSearchRequestDTO search = new TaskLayerSearchRequestDTO();
            search.setLyrGroupCd("rst");
            search.setLyrLclsfCd(lclsfCd);
            List<TaskLayerVO> rstLayers = g2fLayerMapper.selectTaskLayerList(search); //레이어 조회
            
            // USE 조회
            search.setLyrGroupCd("use");
            search.setLyrLclsfCd(null);
            List<TaskLayerVO> useLayers = g2fLayerMapper.selectTaskLayerList(search)
            		.stream()
                    .filter(v -> !"lsmd_cont_ub701".equals(v.getLyrSrvcNm()))  // 경제자유구역 레이어 제외
                    .collect(Collectors.toList());
            
            // lnd 조회
            TaskLayerSearchRequestDTO lndSearch = new TaskLayerSearchRequestDTO();
            lndSearch.setLyrGroupCd("lnd");
            lndSearch.setLyrLclsfCd(null);
            List<TaskLayerVO> lndLayers = g2fLayerMapper
                    .selectTaskLayerList(lndSearch)
                    .stream()
                    .filter(v -> "lsmd_cont_ldreg".equals(v.getLyrSrvcNm()))
                    .collect(Collectors.toList());
            
            // pba 조회
            TaskLayerSearchRequestDTO pbaSearch = new TaskLayerSearchRequestDTO();
            pbaSearch.setLyrGroupCd("pba");
            pbaSearch.setLyrLclsfCd(null);
            List<TaskLayerVO> pbaLayers = g2fLayerMapper
                    .selectTaskLayerList(pbaSearch)
                    .stream()
                    .filter(v ->
                            "tl_scco_ctprvn".equals(v.getLyrSrvcNm())
                         || "tl_scco_sig".equals(v.getLyrSrvcNm())
                         || "tl_scco_emd".equals(v.getLyrSrvcNm())
                         || "tl_scco_li".equals(v.getLyrSrvcNm())
                    )
                    .collect(Collectors.toList());
            
            // 대상 카테고리 필터 
            String prefix = lclsfCd;
            List<ComCdVO> targetCats = allCategories.stream()
                    .filter(c -> c.getCd().equals(prefix) || c.getCd().startsWith(prefix))
                    .collect(Collectors.toList());

            // 레이어를 lclsfCd → List<TaskLayerVO> 로 인덱싱
            Map<String, List<TaskLayerVO>> layerByGroup = rstLayers.stream()
                    .collect(Collectors.groupingBy(
                            RstTaskLyrTreeServiceImpl::key,
                            Collectors.collectingAndThen(
                                    Collectors.toList(),
                                    list -> list.stream()
                                            .sorted(Comparator.comparing(TaskLayerVO::getTaskLyrNm,
                                                    Comparator.nullsLast(Comparator.reverseOrder()))) // DESC + null 안전
                                            .collect(Collectors.toList())
                            )
                    ));

            // 카테고리ID → 노드 미리 생성
            Map<String, RstTaskLayerInfoVO> nodeMap = new java.util.HashMap<>();
            for (ComCdVO cd : targetCats) {
                RstTaskLayerInfoVO node = new RstTaskLayerInfoVO();
                node.setComCdVO(cd);
                node.setTaskLayerList(layerByGroup.getOrDefault(cd.getCd(), java.util.Collections.emptyList()));
                if ("04".equals(cd.getCd())) { // 토지이용현황 레이어
                    node.setUseLayerList(useLayers);
                } else if ("05".equals(cd.getCd())) { // 기본 레이어 (lnd / pba)
                    List<TaskLayerVO> baseLayers = new ArrayList<>();
                    baseLayers.addAll(lndLayers);
                    baseLayers.addAll(pbaLayers);
                    node.setTaskLayerList(baseLayers);
                }
                else {
                    node.setUseLayerList(java.util.Collections.emptyList());
                } 
                node.setChildren(new java.util.ArrayList<>());
                nodeMap.put(cd.getCd(), node);
            }

            // 트리 결선 (upCd 기준으로 parent→children 연결)
            for (ComCdVO cd : targetCats) {
                RstTaskLayerInfoVO cur = nodeMap.get(cd.getCd());
                String up = cd.getUpCd(); // 부모 코드
                if (up == null || up.isEmpty() || !nodeMap.containsKey(up)) {
                    // 최상단
                    if (cd.getCd().equals(prefix) || cd.getCd().startsWith(prefix)) {
                    	if (!"05".equals(cd.getCd())) {
                            cur.setTaskLayerList(layerByGroup.get(cur.getComCdVO().getCd()));
                        }
                        roots.add(cur);
                    }
                } else {
                	if (!"05".equals(cd.getCd())) {
                        cur.setTaskLayerList(layerByGroup.get(cur.getComCdVO().getCd()));
                    }
                    nodeMap.get(up).getChildren().add(cur);
                }
            }

        }catch(Exception e) {
            log.error("=== [오류] 레이어 조회 오류",e.getMessage(), e);
            return roots;
        }
        return roots;
    }

    private static String key(TaskLayerVO v) {
        String m = v.getLyrLclsfCd() != null ? v.getLyrLclsfCd() : ""; //2depth
        return m;
    }

    //카테고리 유효성 검증(UIS 카테고리 여부 확인)
    private boolean isValidCategory(String categoryId) {
        List<ComCdVO> rootCategoryList = rstComCdMapper.getRstRootComCdList();
        return rootCategoryList.stream()
                .anyMatch(c -> categoryId.equals(c.getCd()));
    }
}
