package gc.mda.kcg.menu;

import gc.mda.kcg.permission.PermTree;
import gc.mda.kcg.permission.PermTreeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * auth_perm_tree를 메뉴 SSOT로 사용하여 MenuConfigDto 목록을 생성.
 * 디바이더는 nav_sub_group 변경 시점에 동적 삽입.
 */
@Service
@RequiredArgsConstructor
public class MenuConfigService {

    private final PermTreeRepository permTreeRepository;

    // 메뉴 그룹으로 동작하는 Level-0 노드 rsrc_cd
    private static final Set<String> GROUP_NODES = Set.of(
            "field-ops", "parent-inference-workflow", "admin"
    );

    @Cacheable("menuConfig")
    @Transactional(readOnly = true)
    public List<MenuConfigDto> getActiveMenuConfig() {
        List<PermTree> all = permTreeRepository.findByUseYn("Y");
        List<MenuConfigDto> result = new ArrayList<>();

        // 1) 최상위 ITEM (nav_sort > 0, nav_group IS NULL, url_path IS NOT NULL)
        List<PermTree> topItems = all.stream()
                .filter(n -> n.getNavSort() > 0 && n.getNavGroup() == null && n.getUrlPath() != null)
                .sorted(Comparator.comparingInt(PermTree::getNavSort))
                .toList();
        for (PermTree n : topItems) {
            result.add(toDto(n, null, "ITEM", 0));
        }

        // 2) 그룹 헤더 + 자식 (nav_sort > 0 인 GROUP_NODES)
        List<PermTree> groups = all.stream()
                .filter(n -> GROUP_NODES.contains(n.getRsrcCd()) && n.getNavSort() > 0)
                .sorted(Comparator.comparingInt(PermTree::getNavSort))
                .toList();
        for (PermTree g : groups) {
            result.add(toDto(g, null, "GROUP", 0));

            // 이 그룹의 자식들
            List<PermTree> children = all.stream()
                    .filter(n -> g.getRsrcCd().equals(n.getNavGroup()) && n.getUrlPath() != null)
                    .sorted(Comparator.comparingInt(PermTree::getNavSort))
                    .toList();

            // 디바이더 삽입: nav_sub_group 변경 시점마다
            String currentSubGroup = null;
            int dividerSeq = 0;
            for (PermTree c : children) {
                String sub = c.getNavSubGroup();
                if (sub != null && !sub.equals(currentSubGroup)) {
                    currentSubGroup = sub;
                    dividerSeq++;
                    result.add(new MenuConfigDto(
                            g.getRsrcCd() + ".div-" + dividerSeq,
                            g.getRsrcCd(), "DIVIDER",
                            null, null, null, null, null,
                            sub, 1, c.getNavSort() - 1, "Y",
                            Map.of()
                    ));
                }
                result.add(toDto(c, g.getRsrcCd(), "ITEM", 1));
            }
        }

        // 3) 숨김 라우트 (nav_sort = 0, url_path IS NOT NULL)
        List<PermTree> hidden = all.stream()
                .filter(n -> n.getNavSort() == 0 && n.getUrlPath() != null && !GROUP_NODES.contains(n.getRsrcCd()))
                .toList();
        for (PermTree h : hidden) {
            result.add(new MenuConfigDto(
                    h.getRsrcCd(), null, "ITEM",
                    h.getUrlPath(), h.getRsrcCd(), h.getComponentKey(),
                    h.getIcon(), h.getLabelKey(), null,
                    0, 9999, "H",
                    h.getLabels() != null ? h.getLabels() : Map.of()
            ));
        }

        return result;
    }

    @CacheEvict(value = "menuConfig", allEntries = true)
    public void evictCache() {
    }

    private MenuConfigDto toDto(PermTree n, String parentMenuCd, String menuType, int menuLevel) {
        return new MenuConfigDto(
                n.getRsrcCd(),
                parentMenuCd,
                menuType,
                n.getUrlPath(),
                n.getRsrcCd(),
                n.getComponentKey(),
                n.getIcon(),
                n.getLabelKey(),
                n.getNavSubGroup(),
                menuLevel,
                n.getNavSort(),
                n.getUseYn(),
                n.getLabels() != null ? n.getLabels() : Map.of()
        );
    }
}
