package com.njcn.rdms.module.system.api.permission;

import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
import com.njcn.rdms.module.system.api.permission.dto.ObjectMenuRespDTO;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRolePermissionRespDTO;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleMenuDO;
import com.njcn.rdms.module.system.dal.mysql.permission.MenuMapper;
import com.njcn.rdms.module.system.dal.mysql.permission.RoleMapper;
import com.njcn.rdms.module.system.dal.mysql.permission.RoleMenuMapper;
import com.njcn.rdms.module.system.dal.mysql.permission.UserRoleMapper;
import com.njcn.rdms.module.system.service.permission.MenuServiceImpl;
import com.njcn.rdms.module.system.service.permission.PermissionService;
import com.njcn.rdms.module.system.service.permission.PermissionServiceImpl;
import com.njcn.rdms.module.system.service.permission.RoleService;
import com.njcn.rdms.module.system.service.permission.RoleServiceImpl;
import com.njcn.rdms.module.system.service.user.AdminUserService;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

class ObjectPermissionApiImplTest extends BaseMockitoUnitTest {

    private static final String OBJECT_SCOPE = "object";
    private static final String PRODUCT_OBJECT = "product";
    private static final String GLOBAL_SCOPE = "global";
    private static final String GLOBAL_OBJECT = "";

    @Mock
    private RoleService roleService;
    @Mock
    private PermissionService permissionService;
    @Mock
    private RoleMapper roleMapper;
    @Mock
    private RoleMenuMapper roleMenuMapper;
    @Mock
    private MenuMapper menuMapper;
    @Mock
    private UserRoleMapper userRoleMapper;
    @Mock
    private AdminUserService userService;

    @InjectMocks
    private ObjectPermissionApiImpl objectPermissionApi;

    @Test
    void getObjectRoleById_whenRoleExistsAndEnabled_thenReturnRoleSummary() {
        RoleDO role = buildRole(101L, "qa_owner", "QA Owner", OBJECT_SCOPE, PRODUCT_OBJECT);
        role.setStatus(CommonStatusEnum.ENABLE.getStatus());
        when(roleService.getRole(101L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);

        CommonResult<ObjectRoleRespDTO> result =
                objectPermissionApi.getObjectRoleById(101L, OBJECT_SCOPE, PRODUCT_OBJECT);

        ObjectRoleRespDTO data = result.getCheckedData();
        assertNotNull(data);
        assertEquals(101L, data.getId());
        assertEquals("qa_owner", data.getCode());
        assertEquals("QA Owner", data.getName());
        assertEquals(OBJECT_SCOPE, data.getScopeType());
        assertEquals(PRODUCT_OBJECT, data.getObjectType());
    }

    @Test
    void getObjectRoleById_whenRoleMissing_thenReturnNull() {
        when(roleService.getRole(404L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(null);

        CommonResult<ObjectRoleRespDTO> result =
                objectPermissionApi.getObjectRoleById(404L, OBJECT_SCOPE, PRODUCT_OBJECT);

        assertNull(result.getCheckedData());
    }

    @Test
    void getObjectRoleByCode_whenRoleExists_thenReturnProductManagerRole() {
        RoleDO role = buildRole(102L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        when(roleService.getRoleByCode("product_manager", OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);

        CommonResult<ObjectRoleRespDTO> result =
                objectPermissionApi.getObjectRoleByCode("product_manager", OBJECT_SCOPE, PRODUCT_OBJECT);

        ObjectRoleRespDTO data = result.getCheckedData();
        assertNotNull(data);
        assertEquals(102L, data.getId());
        assertEquals("product_manager", data.getCode());
        assertEquals("Product Manager", data.getName());
    }

    @Test
    void getObjectRoleList_shouldFilterScopedRolesThroughRoleServiceImpl() {
        RoleServiceImpl realRoleService = createRoleServiceImpl();
        ObjectPermissionApiImpl realApi = createObjectPermissionApi(realRoleService, permissionService);
        Map<Long, RoleDO> roleStore = new LinkedHashMap<>();
        roleStore.put(201L, buildRole(201L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT));
        roleStore.put(202L, buildRole(202L, "global_admin", "Global Admin", GLOBAL_SCOPE, GLOBAL_OBJECT));
        roleStore.put(203L, buildRole(203L, "project_manager", "Project Manager", OBJECT_SCOPE, "project"));
        roleStore.put(204L, buildRole(204L, "product_tester", "Product Tester", OBJECT_SCOPE, PRODUCT_OBJECT));
        when(roleMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(roleStore, invocation.getArgument(0)));

        CommonResult<List<ObjectRoleRespDTO>> result =
                realApi.getObjectRoleList(List.of(201L, 202L, 203L, 204L), OBJECT_SCOPE, PRODUCT_OBJECT);

        List<ObjectRoleRespDTO> data = result.getCheckedData();
        assertEquals(List.of(201L, 204L), data.stream().map(ObjectRoleRespDTO::getId).toList());
        assertEquals(List.of("product_manager", "product_tester"),
                data.stream().map(ObjectRoleRespDTO::getCode).toList());
    }

    @Test
    void getObjectRolePermissions_whenRoleMissing_thenReturnEmptySet() {
        when(roleService.getRole(303L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(null);

        CommonResult<Set<String>> result =
                objectPermissionApi.getObjectRolePermissions(303L, OBJECT_SCOPE, PRODUCT_OBJECT);

        assertTrue(result.getCheckedData().isEmpty());
        verifyNoInteractions(permissionService);
    }

    @Test
    void getObjectRolePermissions_whenRoleDisabled_thenReturnEmptySet() {
        RoleDO role = buildRole(304L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        role.setStatus(CommonStatusEnum.DISABLE.getStatus());
        when(roleService.getRole(304L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);

        CommonResult<Set<String>> result =
                objectPermissionApi.getObjectRolePermissions(304L, OBJECT_SCOPE, PRODUCT_OBJECT);

        assertTrue(result.getCheckedData().isEmpty());
        verifyNoInteractions(permissionService);
    }

    @Test
    void permissionServiceImpl_getScopedPermissionsByRoleId_shouldExtractButtonPermissionFromEffectiveMenus() {
        MenuServiceImpl realMenuService = createMenuServiceImpl();
        PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
        RoleDO role = buildRole(301L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        MenuDO menu = buildMenu(3011L, "Product Setting", null, 2, 10, "/product/setting",
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
        MenuDO button = buildMenu(3012L, "Save", "project:product:update", 3, 20, null,
                3011L, CommonStatusEnum.ENABLE.getStatus());
        Map<Long, MenuDO> menuStore = menuStore(menu, button);
        when(roleService.getRole(301L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
        when(roleService.getRoleList(Collections.singleton(301L), OBJECT_SCOPE, PRODUCT_OBJECT))
                .thenReturn(List.of(role));
        when(roleMenuMapper.selectListByRoleId(Collections.singleton(301L)))
                .thenReturn(List.of(buildRoleMenu(301L, 3011L), buildRoleMenu(301L, 3012L)));
        when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));

        Set<String> permissions = realPermissionService.getScopedPermissionsByRoleId(301L, OBJECT_SCOPE, PRODUCT_OBJECT);

        assertEquals(Set.of("project:product:update"), permissions);
    }

    @Test
    void permissionServiceImpl_getScopedMenusAndPermissionsByRoleId_shouldReturnEmptyResultsWhenRoleIsDisabled() {
        MenuServiceImpl realMenuService = createMenuServiceImpl();
        PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
        RoleDO disabledRole = buildRole(305L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        disabledRole.setStatus(CommonStatusEnum.DISABLE.getStatus());
        when(roleService.getRole(305L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(disabledRole);

        List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(305L, OBJECT_SCOPE, PRODUCT_OBJECT);
        Set<String> permissions = realPermissionService.getScopedPermissionsByRoleId(305L, OBJECT_SCOPE, PRODUCT_OBJECT);

        assertTrue(menus.isEmpty());
        assertTrue(permissions.isEmpty());
        verifyNoInteractions(roleMenuMapper, menuMapper);
    }

    @Test
    void permissionServiceImpl_getScopedMenusAndPermissionsByRoleId_shouldIgnoreMenusOutsideRequestedScopeAndObject() {
        MenuServiceImpl realMenuService = createMenuServiceImpl();
        PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
        RoleDO role = buildRole(3051L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        MenuDO directory = buildMenu(30511L, "Product", null, 1, 1, "/product",
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
        MenuDO scopedButton = buildMenu(30512L, "Save", "project:product:update", 3, 10, null,
                30511L, CommonStatusEnum.ENABLE.getStatus());
        MenuDO globalButton = buildMenu(30513L, "Global Export", "system:global:export", 3, 20, null,
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus(), GLOBAL_SCOPE, GLOBAL_OBJECT);
        MenuDO otherObjectButton = buildMenu(30514L, "Project Publish", "project:project:publish", 3, 30, null,
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus(), OBJECT_SCOPE, "project");
        Map<Long, MenuDO> menuStore = menuStore(directory, scopedButton, globalButton, otherObjectButton);
        when(roleService.getRole(3051L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
        when(roleService.getRoleList(Collections.singleton(3051L), OBJECT_SCOPE, PRODUCT_OBJECT))
                .thenReturn(List.of(role));
        when(roleMenuMapper.selectListByRoleId(Collections.singleton(3051L)))
                .thenReturn(List.of(buildRoleMenu(3051L, 30511L), buildRoleMenu(3051L, 30512L),
                        buildRoleMenu(3051L, 30513L),
                        buildRoleMenu(3051L, 30514L)));
        when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));

        List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(3051L, OBJECT_SCOPE, PRODUCT_OBJECT);
        Set<String> permissions = realPermissionService.getScopedPermissionsByRoleId(3051L, OBJECT_SCOPE, PRODUCT_OBJECT);

        assertEquals(Set.of(30511L, 30512L),
                menus.stream().map(MenuDO::getId).collect(LinkedHashSet::new, Set::add, Set::addAll));
        assertEquals(Set.of("project:product:update"), permissions);
    }

    @Test
    void permissionServiceImpl_getRoleMenuListByRoleIdScopedCollection_shouldExcludeDisabledRoles() {
        MenuServiceImpl realMenuService = createMenuServiceImpl();
        PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
        RoleDO enabledRole = buildRole(306L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        RoleDO disabledRole = buildRole(307L, "product_viewer", "Product Viewer", OBJECT_SCOPE, PRODUCT_OBJECT);
        disabledRole.setStatus(CommonStatusEnum.DISABLE.getStatus());
        MenuDO enabledMenu = buildMenu(3061L, "Enabled Menu", null, 2, 10, "/product/enabled",
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
        MenuDO disabledRoleMenu = buildMenu(3071L, "Disabled Role Menu", null, 2, 20, "/product/disabled-role",
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
        Map<Long, MenuDO> menuStore = menuStore(enabledMenu, disabledRoleMenu);
        when(roleService.getRoleList(List.of(306L, 307L), OBJECT_SCOPE, PRODUCT_OBJECT))
                .thenReturn(List.of(enabledRole, disabledRole));
        when(roleMenuMapper.selectListByRoleId(org.mockito.ArgumentMatchers.<Collection<Long>>any())).thenAnswer(invocation -> {
            Collection<Long> roleIds = invocation.getArgument(0);
            List<RoleMenuDO> results = new ArrayList<>();
            if (roleIds.contains(306L)) {
                results.add(buildRoleMenu(306L, 3061L));
            }
            if (roleIds.contains(307L)) {
                results.add(buildRoleMenu(307L, 3071L));
            }
            return results;
        });
        when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));

        Set<Long> menuIds = realPermissionService.getRoleMenuListByRoleId(List.of(306L, 307L), OBJECT_SCOPE, PRODUCT_OBJECT);

        assertEquals(Set.of(3061L), menuIds);
    }

    @Test
    void getObjectRolePermissionDetail_whenRoleMissing_thenReturnEmptyDetail() {
        when(roleService.getRole(401L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(null);

        CommonResult<ObjectRolePermissionRespDTO> result =
                objectPermissionApi.getObjectRolePermissionDetail(401L, OBJECT_SCOPE, PRODUCT_OBJECT);

        ObjectRolePermissionRespDTO detail = result.getCheckedData();
        assertNotNull(detail);
        assertNull(detail.getCurrentRole());
        assertTrue(detail.getMenus().isEmpty());
        assertTrue(detail.getPermissions().isEmpty());
        verifyNoInteractions(permissionService);
    }

    @Test
    void getObjectRolePermissionDetail_whenRoleDisabled_thenReturnEmptyDetail() {
        RoleDO role = buildRole(405L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        role.setStatus(CommonStatusEnum.DISABLE.getStatus());
        when(roleService.getRole(405L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);

        CommonResult<ObjectRolePermissionRespDTO> result =
                objectPermissionApi.getObjectRolePermissionDetail(405L, OBJECT_SCOPE, PRODUCT_OBJECT);

        ObjectRolePermissionRespDTO detail = result.getCheckedData();
        assertNotNull(detail);
        assertNull(detail.getCurrentRole());
        assertTrue(detail.getMenus().isEmpty());
        assertTrue(detail.getPermissions().isEmpty());
        verifyNoInteractions(permissionService);
    }

    @Test
    void getObjectRolePermissionDetail_shouldAggregateRoleMenusAndPermissions() {
        RoleDO role = buildRole(402L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        MenuDO directory = buildMenu(11L, "Product", null, 1, 1, "/product",
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
        MenuDO menu = buildMenu(12L, "Product Setting", null, 2, 10, "/product/setting",
                11L, CommonStatusEnum.ENABLE.getStatus());
        MenuDO button = buildMenu(13L, "Save", "project:product:update", 3, 20, null,
                12L, CommonStatusEnum.ENABLE.getStatus());
        Set<String> permissions = new LinkedHashSet<>(Set.of("project:product:update"));
        when(roleService.getRole(402L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
        when(permissionService.getScopedMenusByRoleId(402L, OBJECT_SCOPE, PRODUCT_OBJECT))
                .thenReturn(List.of(directory, menu, button));
        when(permissionService.getScopedPermissionsByRoleId(402L, OBJECT_SCOPE, PRODUCT_OBJECT))
                .thenReturn(permissions);

        CommonResult<ObjectRolePermissionRespDTO> result =
                objectPermissionApi.getObjectRolePermissionDetail(402L, OBJECT_SCOPE, PRODUCT_OBJECT);

        ObjectRolePermissionRespDTO detail = result.getCheckedData();
        assertNotNull(detail.getCurrentRole());
        assertEquals(3, detail.getMenus().size());
        assertEquals(List.of(11L, 12L, 13L), detail.getMenus().stream().map(ObjectMenuRespDTO::getId).toList());
        assertEquals(permissions, detail.getPermissions());
    }

    @Test
    void permissionServiceImpl_getScopedMenusByRoleId_shouldExcludeDisabledMenus() {
        MenuServiceImpl realMenuService = createMenuServiceImpl();
        PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
        RoleDO role = buildRole(403L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        MenuDO enabledMenu = buildMenu(21L, "Enabled Menu", null, 2, 10, "/product/setting",
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
        MenuDO disabledMenu = buildMenu(22L, "Disabled Menu", null, 2, 20, "/product/disabled",
                MenuDO.ID_ROOT, CommonStatusEnum.DISABLE.getStatus());
        Map<Long, MenuDO> menuStore = menuStore(enabledMenu, disabledMenu);
        when(roleService.getRole(403L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
        when(roleService.getRoleList(Collections.singleton(403L), OBJECT_SCOPE, PRODUCT_OBJECT))
                .thenReturn(List.of(role));
        when(roleMenuMapper.selectListByRoleId(Collections.singleton(403L)))
                .thenReturn(List.of(buildRoleMenu(403L, 21L), buildRoleMenu(403L, 22L)));
        when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));

        List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(403L, OBJECT_SCOPE, PRODUCT_OBJECT);

        List<Long> menuIds = menus.stream().map(MenuDO::getId).toList();
        assertEquals(List.of(21L), menuIds);
        assertFalse(menuIds.contains(22L));
    }

    void permissionServiceImpl_getScopedMenusByRoleId_shouldKeepAncestorMenusAfterExpandedRoleMenuAssignments() {
        MenuServiceImpl realMenuService = createMenuServiceImpl();
        PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
        RoleDO role = buildRole(404L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
        MenuDO directory = buildMenu(31L, "Product", null, 1, 1, "/product",
                MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
        MenuDO childMenu = buildMenu(32L, "Product Setting", null, 2, 10, "/product/setting",
                31L, CommonStatusEnum.ENABLE.getStatus());
        MenuDO button = buildMenu(33L, "Save", "project:product:update", 3, 20, null,
                32L, CommonStatusEnum.ENABLE.getStatus());
        Map<Long, MenuDO> menuStore = menuStore(directory, childMenu, button);
        List<RoleMenuDO> persistedRoleMenus = new ArrayList<>();
        when(roleService.getRole(404L)).thenReturn(role);
        when(roleService.getRole(404L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
        when(roleService.getRoleList(Collections.singleton(404L), OBJECT_SCOPE, PRODUCT_OBJECT))
                .thenReturn(List.of(role));
        when(roleMenuMapper.selectListByRoleId(404L)).thenReturn(Collections.emptyList());
        doAnswer(invocation -> {
            persistedRoleMenus.clear();
            persistedRoleMenus.addAll(invocation.getArgument(0));
            return null;
        }).when(roleMenuMapper).insertBatch(any());
        when(roleMenuMapper.selectListByRoleId(Collections.singleton(404L)))
                .thenAnswer(invocation -> new ArrayList<>(persistedRoleMenus));
        when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));

        realPermissionService.assignRoleMenu(404L, Set.of(32L, 33L));
        List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(404L, OBJECT_SCOPE, PRODUCT_OBJECT);

        assertEquals(Set.of(31L, 32L, 33L), menus.stream().map(MenuDO::getId).collect(LinkedHashSet::new, Set::add, Set::addAll));
        assertEquals(Set.of("Product", "Product Setting", "Save"),
                menus.stream().map(MenuDO::getName).collect(LinkedHashSet::new, Set::add, Set::addAll));
    }

    private RoleServiceImpl createRoleServiceImpl() {
        RoleServiceImpl roleServiceImpl = new RoleServiceImpl();
        ReflectionTestUtils.setField(roleServiceImpl, "permissionService", permissionService);
        ReflectionTestUtils.setField(roleServiceImpl, "roleMapper", roleMapper);
        ReflectionTestUtils.setField(roleServiceImpl, "userRoleMapper", userRoleMapper);
        return roleServiceImpl;
    }

    private MenuServiceImpl createMenuServiceImpl() {
        MenuServiceImpl menuServiceImpl = new MenuServiceImpl();
        ReflectionTestUtils.setField(menuServiceImpl, "menuMapper", menuMapper);
        ReflectionTestUtils.setField(menuServiceImpl, "permissionService", permissionService);
        return menuServiceImpl;
    }

    private PermissionServiceImpl createPermissionServiceImpl(RoleService roleServiceDependency,
                                                              MenuServiceImpl menuServiceDependency) {
        PermissionServiceImpl permissionServiceImpl = new PermissionServiceImpl();
        ReflectionTestUtils.setField(permissionServiceImpl, "roleMenuMapper", roleMenuMapper);
        ReflectionTestUtils.setField(permissionServiceImpl, "userRoleMapper", userRoleMapper);
        ReflectionTestUtils.setField(permissionServiceImpl, "roleService", roleServiceDependency);
        ReflectionTestUtils.setField(permissionServiceImpl, "menuService", menuServiceDependency);
        ReflectionTestUtils.setField(permissionServiceImpl, "userService", userService);
        return permissionServiceImpl;
    }

    private ObjectPermissionApiImpl createObjectPermissionApi(RoleService roleServiceDependency,
                                                              PermissionService permissionServiceDependency) {
        ObjectPermissionApiImpl api = new ObjectPermissionApiImpl();
        ReflectionTestUtils.setField(api, "roleService", roleServiceDependency);
        ReflectionTestUtils.setField(api, "permissionService", permissionServiceDependency);
        return api;
    }

    private static RoleDO buildRole(Long id, String code, String name, String scopeType, String objectType) {
        RoleDO role = new RoleDO();
        role.setId(id);
        role.setCode(code);
        role.setName(name);
        role.setScopeType(scopeType);
        role.setObjectType(objectType);
        role.setStatus(CommonStatusEnum.ENABLE.getStatus());
        return role;
    }

    private static MenuDO buildMenu(Long id, String name, String permission, Integer type, Integer sort, String path,
                                    Long parentId, Integer status) {
        return buildMenu(id, name, permission, type, sort, path, parentId, status, OBJECT_SCOPE, PRODUCT_OBJECT);
    }

    private static MenuDO buildMenu(Long id, String name, String permission, Integer type, Integer sort, String path,
                                    Long parentId, Integer status, String scopeType, String objectType) {
        MenuDO menu = new MenuDO();
        menu.setId(id);
        menu.setName(name);
        menu.setPermission(permission);
        menu.setType(type);
        menu.setSort(sort);
        menu.setPath(path);
        menu.setParentId(parentId);
        menu.setStatus(status);
        menu.setVisible(Boolean.TRUE);
        menu.setScopeType(scopeType);
        menu.setObjectType(objectType);
        return menu;
    }

    private static RoleMenuDO buildRoleMenu(Long roleId, Long menuId) {
        RoleMenuDO roleMenu = new RoleMenuDO();
        roleMenu.setRoleId(roleId);
        roleMenu.setMenuId(menuId);
        return roleMenu;
    }

    private static <T> List<T> selectValues(Map<Long, T> store, Collection<Long> ids) {
        return ids.stream()
                .map(store::get)
                .filter(Objects::nonNull)
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
    }

    private static Map<Long, MenuDO> menuStore(MenuDO... menus) {
        Map<Long, MenuDO> results = new LinkedHashMap<>();
        for (MenuDO menu : menus) {
            results.put(menu.getId(), menu);
        }
        return results;
    }

}
