package incheon.uis.ums.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;

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.uis.ums.mapper.UisComCdMapper;
import incheon.uis.ums.service.UisAccessService;
import incheon.uis.ums.service.UisTaskLyrTreeService;
import incheon.uis.ums.vo.UisTaskLayerInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
@RequiredArgsConstructor
public class UisTaskLyrTreeServiceImpl implements UisTaskLyrTreeService {

    private final G2FLayerMapper g2fLayerMapper;
    private final UisComCdMapper uisComCdMapper;
    private final UisAccessService uisAccessService;
    
    @Override
    public List<UisTaskLayerInfoVO> getTaskLyrTreeInfo(String groupCd) {

        List<UisTaskLayerInfoVO> roots = new ArrayList<>();

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

        // 2) 사용자 권한 체크
        if (!uisAccessService.hasAuthrtAccessByGroupCd(groupCd)) {
            throw new AccessDeniedException("해당 카테고리에 대한 접근 권한이 없습니다.");
        }

        try {
            // 3) 코드/레이어 조회
            List<ComCdVO> allCategories = uisComCdMapper.getUisComCdList(); // UIS Category 조회
            TaskLayerSearchRequestDTO search = new TaskLayerSearchRequestDTO();
            search.setLyrGroupCd(groupCd);
            List<TaskLayerVO> layers = g2fLayerMapper.selectTaskLayerList(search); // 레이어 조회

            // 4) 루트 기준으로 “필요한 카테고리만” 추출 (접두 기반)
            String prefix = groupCd;
            List<ComCdVO> targetCats = allCategories.stream()
                    .filter(c -> c.getCd().equals(prefix) || c.getCd().startsWith(prefix))
                    .collect(Collectors.toList());

            // 5) 레이어를 groupCd → List<TaskLayerVO> 로 인덱싱
            Map<String, List<TaskLayerVO>> layerByGroup = layers.stream()
                    .collect(Collectors.groupingBy(
                            UisTaskLyrTreeServiceImpl::key,
                            Collectors.collectingAndThen(
                                    Collectors.toList(),
                                    list -> list.stream()
                                            .sorted(Comparator.comparing(
                                                    TaskLayerVO::getTaskLyrNm,
                                                    Comparator.nullsLast(Comparator.reverseOrder())
                                            ))
                                            .collect(Collectors.toList())
                            )
                    ));

            // 6) 카테고리ID → 노드 미리 생성
            Map<String, UisTaskLayerInfoVO> nodeMap = new HashMap<>();
            for (ComCdVO cd : targetCats) {
                UisTaskLayerInfoVO node = new UisTaskLayerInfoVO();
                node.setComCdVO(cd);
                node.setTaskLayerList(layerByGroup.getOrDefault(cd.getCd(), Collections.emptyList()));
                node.setChildren(new ArrayList<>());
                nodeMap.put(cd.getCd(), node);
            }

            // 7) 트리 결선 (upCd 기준으로 parent → children 연결)
            for (ComCdVO cd : targetCats) {
                UisTaskLayerInfoVO cur = nodeMap.get(cd.getCd());
                String up = cd.getUpCd();

                if (up == null || up.isEmpty() || !nodeMap.containsKey(up)) {
                    // 최상단
                    cur.setTaskLayerList(layerByGroup.get(cur.getComCdVO().getCd()));
                    roots.add(cur);
                } else {
                    cur.setTaskLayerList(layerByGroup.get(cur.getComCdVO().getCd()));
                    nodeMap.get(up).getChildren().add(cur);
                }
            }

            return roots;

        } catch (RuntimeException e) {
            // DB / 매퍼 / 스트림 처리 중 발생한 예외
            log.error("[레이어 트리 조회 실패] groupCd={}", groupCd, e);
            return roots;
        }
    }


    private static String key(TaskLayerVO v) {
        String g = v.getLyrGroupCd() != null ? v.getLyrGroupCd() : ""; //1depth
        String m = v.getLyrMclsfCd() != null ? v.getLyrMclsfCd() : ""; //2depth
        String s = v.getLyrSclsfCd() != null ? v.getLyrSclsfCd() : ""; //3depth
        return g + m + s;
    }

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