package com.njcn.rdms.module.project.service.datascope;

import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
import com.njcn.rdms.module.project.dal.dataobject.member.UserObjectRoleDO;
import com.njcn.rdms.module.project.dal.mysql.member.UserObjectRoleMapper;
import com.njcn.rdms.module.system.api.dept.OrgLeaderApi;
import com.njcn.rdms.module.system.api.permission.PermissionApi;
import com.njcn.rdms.module.system.api.permission.UserVisibilityConfigApi;
import com.njcn.rdms.module.system.api.permission.dto.UserVisibilityConfigRespDTO;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import java.util.List;
import java.util.Set;

import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

class ObjectDataScopeServiceImplTest extends BaseMockitoUnitTest {

    @InjectMocks
    private ObjectDataScopeServiceImpl service;

    @Mock
    private PermissionApi permissionApi;

    @Mock
    private UserObjectRoleMapper userObjectRoleMapper;

    @Mock
    private OrgLeaderApi orgLeaderApi;

    @Mock
    private UserVisibilityConfigApi userVisibilityConfigApi;

    @Test
    void compute_returnsAll_whenUserIsSuperAdmin() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(true));
        ObjectDataScope scope = service.compute(1L, "project");
        assertThat(scope.getState()).isEqualTo(ObjectDataScope.State.ALL);
    }

    // ---- helper ----

    private static UserObjectRoleDO row(Long objectId) {
        UserObjectRoleDO r = new UserObjectRoleDO();
        r.setObjectId(objectId);
        return r;
    }

    private static UserVisibilityConfigRespDTO cfg(String type, Set<String> directionCodes) {
        UserVisibilityConfigRespDTO dto = new UserVisibilityConfigRespDTO();
        dto.setType(type);
        dto.setDirectionCodes(directionCodes);
        return dto;
    }

    // ---- task 0.4 旧 case（补通道 2 + 通道 3 mock，strict mode 不报未预期调用）----

    @Test
    void compute_returnsEmpty_whenNonSuperAdminAndNoChannelMatch() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(false));
        when(userObjectRoleMapper.selectActiveListByObjectTypeAndUserId("project", 1L)).thenReturn(List.of());
        when(orgLeaderApi.getReachableUserIds(1L)).thenReturn(success(Set.of()));
        when(userVisibilityConfigApi.getConfig(1L)).thenReturn(success(null));
        ObjectDataScope scope = service.compute(1L, "project");
        assertThat(scope.getState()).isEqualTo(ObjectDataScope.State.EMPTY);
    }

    @Test
    void compute_returnsIdList_withChannel1Hits() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(false));
        when(userObjectRoleMapper.selectActiveListByObjectTypeAndUserId("project", 1L))
                .thenReturn(List.of(row(101L), row(102L)));
        when(orgLeaderApi.getReachableUserIds(1L)).thenReturn(success(Set.of()));
        when(userVisibilityConfigApi.getConfig(1L)).thenReturn(success(null));

        ObjectDataScope scope = service.compute(1L, "project");
        assertThat(scope.getState()).isEqualTo(ObjectDataScope.State.ID_LIST);
        assertThat(scope.getIds()).containsExactlyInAnyOrder(101L, 102L);
    }

    // ---- task 1.4 新 case ----

    @Test
    void compute_unionsChannel1AndChannel2_whenUserIsLeader() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(false));
        // 通道 1 命中 101
        when(userObjectRoleMapper.selectActiveListByObjectTypeAndUserId("project", 1L))
                .thenReturn(List.of(row(101L)));
        // 通道 2 命中 102 / 103
        when(orgLeaderApi.getReachableUserIds(1L)).thenReturn(success(Set.of(2L, 3L)));
        when(userObjectRoleMapper.selectListByUserIdsAndObjectType(Set.of(2L, 3L), "project"))
                .thenReturn(List.of(row(102L), row(103L)));
        when(userVisibilityConfigApi.getConfig(1L)).thenReturn(success(null));

        ObjectDataScope scope = service.compute(1L, "project");
        assertThat(scope.getIds()).containsExactlyInAnyOrder(101L, 102L, 103L);
    }

    @Test
    void compute_skipsChannel2_whenUserIsNotLeader() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(false));
        when(userObjectRoleMapper.selectActiveListByObjectTypeAndUserId("project", 1L))
                .thenReturn(List.of());
        when(orgLeaderApi.getReachableUserIds(1L)).thenReturn(success(Set.of()));
        when(userVisibilityConfigApi.getConfig(1L)).thenReturn(success(null));
        ObjectDataScope scope = service.compute(1L, "project");
        assertThat(scope.getState()).isEqualTo(ObjectDataScope.State.EMPTY);
    }

    // ---- task 2.6 新 case：通道 3 ----

    @Test
    void compute_returnsAll_whenChannel3IsAll() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(false));
        when(userObjectRoleMapper.selectActiveListByObjectTypeAndUserId("project", 1L)).thenReturn(List.of());
        when(orgLeaderApi.getReachableUserIds(1L)).thenReturn(success(Set.of()));
        when(userVisibilityConfigApi.getConfig(1L)).thenReturn(success(cfg("all", null)));
        ObjectDataScope scope = service.compute(1L, "project");
        assertThat(scope.getState()).isEqualTo(ObjectDataScope.State.ALL);
    }

    @Test
    void compute_addsDirectionCodes_whenChannel3IsDirections() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(false));
        when(userObjectRoleMapper.selectActiveListByObjectTypeAndUserId("project", 1L)).thenReturn(List.of());
        when(orgLeaderApi.getReachableUserIds(1L)).thenReturn(success(Set.of()));
        when(userVisibilityConfigApi.getConfig(1L)).thenReturn(success(cfg("directions", Set.of("system", "embedded"))));
        ObjectDataScope scope = service.compute(1L, "project");
        assertThat(scope.getState()).isEqualTo(ObjectDataScope.State.ID_LIST);
        assertThat(scope.getIds()).isEmpty();
        assertThat(scope.getDirectionCodes()).containsExactlyInAnyOrder("system", "embedded");
    }

    @Test
    void compute_ignoresChannel3_whenTypeIsProjects() {
        when(permissionApi.isSuperAdmin(1L)).thenReturn(success(false));
        when(userObjectRoleMapper.selectActiveListByObjectTypeAndUserId("project", 1L)).thenReturn(List.of());
        when(orgLeaderApi.getReachableUserIds(1L)).thenReturn(success(Set.of()));
        UserVisibilityConfigRespDTO projectsCfg = new UserVisibilityConfigRespDTO();
        projectsCfg.setType("projects");
        projectsCfg.setProjectIds(Set.of(101L, 102L));
        when(userVisibilityConfigApi.getConfig(1L)).thenReturn(success(projectsCfg));
        ObjectDataScope scope = service.compute(1L, "project");
        // 业务暂不消费 projects 类型 → ids/directionCodes 都空 → EMPTY
        assertThat(scope.getState()).isEqualTo(ObjectDataScope.State.EMPTY);
    }
}
