package com.ga.common.menu;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

class MenuTreeBuilderTest {

    private MenuVO menu(Long id, Long parentId, String code, int sort) {
        MenuVO m = new MenuVO();
        m.setMenuId(id);
        m.setParentMenuId(parentId);
        m.setMenuCode(code);
        m.setMenuName(code + "-name");
        m.setMenuType("PAGE");
        m.setSortOrder(sort);
        m.setIsActive("Y");
        return m;
    }

    @Test
    @DisplayName("부모-자식 연결: parent_menu_id 가 null 이면 root")
    void buildTree_basic() {
        List<MenuVO> flat = List.of(
                menu(1L, null, "ROOT_A", 1),
                menu(2L, 1L,   "A_CHILD_1", 2),
                menu(3L, 1L,   "A_CHILD_2", 1),
                menu(4L, null, "ROOT_B", 2)
        );

        List<MenuResp> roots = MenuTreeBuilder.build(flat, Map.of());

        assertThat(roots).hasSize(2);
        // root 도 sortOrder 로 정렬됨
        assertThat(roots.get(0).getMenuCode()).isEqualTo("ROOT_A");
        assertThat(roots.get(1).getMenuCode()).isEqualTo("ROOT_B");

        // ROOT_A 의 자식이 sortOrder 순으로 정렬되었는지
        List<MenuResp> aChildren = roots.get(0).getChildren();
        assertThat(aChildren).hasSize(2);
        assertThat(aChildren.get(0).getMenuCode()).isEqualTo("A_CHILD_2"); // sort 1
        assertThat(aChildren.get(1).getMenuCode()).isEqualTo("A_CHILD_1"); // sort 2
        assertThat(roots.get(1).getChildren()).isEmpty();
    }

    @Test
    @DisplayName("permissionsByMenuId: menuId 별 권한 코드 주입")
    void permissions_injected() {
        List<MenuVO> flat = List.of(menu(10L, null, "M", 1));
        Map<Long, List<String>> perms = Map.of(10L, List.of("READ", "CREATE", "UPDATE"));

        List<MenuResp> roots = MenuTreeBuilder.build(flat, perms);

        assertThat(roots.get(0).getPermissions()).containsExactly("READ", "CREATE", "UPDATE");
    }

    @Test
    @DisplayName("permissionsByMenuId 없는 메뉴는 빈 리스트")
    void permissions_emptyDefault() {
        List<MenuVO> flat = List.of(menu(10L, null, "M", 1));
        List<MenuResp> roots = MenuTreeBuilder.build(flat, Map.of());

        assertThat(roots.get(0).getPermissions()).isEmpty();
    }

    @Test
    @DisplayName("부모가 목록에 없는 고아 메뉴는 root 로 끌어올림")
    void orphan_promotedToRoot() {
        List<MenuVO> flat = List.of(
                menu(1L, null, "ROOT", 1),
                menu(99L, 999L, "ORPHAN", 1) // 부모 999가 목록에 없음
        );

        List<MenuResp> roots = MenuTreeBuilder.build(flat, Map.of());

        // 둘 다 root 로 처리되어야 함
        assertThat(roots).hasSize(2);
        assertThat(roots).extracting(MenuResp::getMenuCode).containsExactlyInAnyOrder("ROOT", "ORPHAN");
    }

    @Test
    @DisplayName("3단계 계층: 손자까지 연결되고 각 레벨 sortOrder 정렬")
    void threeLevels() {
        List<MenuVO> flat = List.of(
                menu(1L, null, "L1", 1),
                menu(2L, 1L,   "L2", 1),
                menu(3L, 2L,   "L3_B", 2),
                menu(4L, 2L,   "L3_A", 1)
        );

        List<MenuResp> roots = MenuTreeBuilder.build(flat, Map.of());

        MenuResp l2 = roots.get(0).getChildren().get(0);
        assertThat(l2.getMenuCode()).isEqualTo("L2");
        assertThat(l2.getChildren()).extracting(MenuResp::getMenuCode)
                .containsExactly("L3_A", "L3_B"); // sortOrder 정렬
    }

    @Test
    @DisplayName("permissionsByMenuId 가 null 이면 권한 주입 스킵")
    void permissionsByMenuId_null_skipsInjection() {
        List<MenuVO> flat = List.of(menu(10L, null, "M", 1));

        List<MenuResp> roots = MenuTreeBuilder.build(flat, null);

        // 기본값(빈 리스트) 그대로 유지
        assertThat(roots.get(0).getPermissions()).isEmpty();
    }
}
