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

import com.njcn.rdms.framework.common.exception.ServiceException;
import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
import com.njcn.rdms.module.project.controller.admin.product.vo.member.ProductMemberRespVO;
import com.njcn.rdms.module.project.controller.admin.product.vo.member.ProductMemberSaveReqVO;
import com.njcn.rdms.module.project.controller.admin.product.vo.member.ProductMemberUpdateReqVO;
import com.njcn.rdms.module.project.dal.dataobject.audit.BizAuditLogDO;
import com.njcn.rdms.module.project.dal.dataobject.member.UserObjectRoleDO;
import com.njcn.rdms.module.project.dal.dataobject.product.ProductDO;
import com.njcn.rdms.module.project.dal.mysql.audit.BizAuditLogMapper;
import com.njcn.rdms.module.project.dal.mysql.member.UserObjectRoleMapper;
import com.njcn.rdms.module.project.dal.mysql.product.ProductMapper;
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
import com.njcn.rdms.module.system.api.user.AdminUserApi;
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class ProductMemberServiceImplTest extends BaseMockitoUnitTest {

    @InjectMocks
    private ProductMemberServiceImpl productMemberService;
    @Mock
    private ProductMapper productMapper;
    @Mock
    private UserObjectRoleMapper userObjectRoleMapper;
    @Mock
    private ObjectPermissionApi objectPermissionApi;
    @Mock
    private BizAuditLogMapper bizAuditLogMapper;
    @Mock
    private AdminUserApi adminUserApi;

    @Test
    void getProductMemberList_shouldFillRoleNameAndRoleCodeFromObjectPermissionApi() {
        Long productId = 1001L;
        ProductDO product = createProduct(productId, 2001L);
        UserObjectRoleDO manager = createMember(9001L, productId, 2001L, 3101L, 0);
        UserObjectRoleDO member = createMember(9002L, productId, 2002L, 3102L, 0);
        when(productMapper.selectById(productId)).thenReturn(product);
        when(userObjectRoleMapper.selectListByObject("product", productId)).thenReturn(List.of(manager, member));
        when(objectPermissionApi.getObjectRoleList(Set.of(3101L, 3102L), "object", "product"))
                .thenReturn(success(List.of(
                        createRole(3101L, "product_manager", "产品经理"),
                        createRole(3102L, "product_member", "产品成员")
                )));
        when(adminUserApi.getUserMap(Set.of(2001L, 2002L))).thenReturn(Map.of(
                2001L, createUser("经理甲"),
                2002L, createUser("成员乙")
        ));

        List<ProductMemberRespVO> respVOList = productMemberService.getProductMemberList(productId);

        assertEquals(2, respVOList.size());
        assertEquals("产品经理", respVOList.get(0).getRoleName());
        assertEquals("product_manager", respVOList.get(0).getRoleCode());
        assertEquals(Boolean.TRUE, respVOList.get(0).getManagerFlag());
        assertEquals("产品成员", respVOList.get(1).getRoleName());
        assertEquals("product_member", respVOList.get(1).getRoleCode());
        assertFalse(respVOList.get(1).getManagerFlag());
    }

    @Test
    void createProductMember_whenRoleSummaryMissing_shouldThrowRoleInvalid() {
        Long productId = 1002L;
        ProductMemberSaveReqVO reqVO = new ProductMemberSaveReqVO();
        reqVO.setUserId(2003L);
        reqVO.setRoleId(3999L);
        when(productMapper.selectById(productId)).thenReturn(createProduct(productId, 2001L));
        when(objectPermissionApi.getObjectRoleById(3999L, "object", "product")).thenReturn(success(null));

        ServiceException ex = assertThrows(ServiceException.class,
                () -> productMemberService.createProductMember(productId, reqVO));

        assertEquals(ErrorCodeConstants.PRODUCT_MEMBER_ROLE_INVALID.getCode(), ex.getCode());
        verify(userObjectRoleMapper, never()).selectByObjectAndUserId(any(), any(), any());
    }

    @Test
    void updateProductMember_whenPreviousManagerRoleCodeStillManager_shouldThrowException() {
        Long productId = 1003L;
        Long memberId = 9003L;
        Long currentManagerUserId = 2001L;
        Long targetManagerRoleId = 3201L;
        Long previousManagerRoleId = 3202L;
        ProductMemberUpdateReqVO reqVO = new ProductMemberUpdateReqVO();
        reqVO.setRoleId(targetManagerRoleId);
        reqVO.setPreviousManagerUserId(currentManagerUserId);
        reqVO.setPreviousManagerRoleId(previousManagerRoleId);
        reqVO.setReason("角色交接");

        ProductDO product = createProduct(productId, currentManagerUserId);
        UserObjectRoleDO member = createMember(memberId, productId, 2002L, 3203L, 0);
        when(productMapper.selectById(productId)).thenReturn(product);
        when(userObjectRoleMapper.selectByIdAndObject(memberId, "product", productId)).thenReturn(member);
        when(objectPermissionApi.getObjectRoleById(targetManagerRoleId, "object", "product"))
                .thenReturn(success(createRole(targetManagerRoleId, "product_manager", "产品经理")));
        when(objectPermissionApi.getObjectRoleById(previousManagerRoleId, "object", "product"))
                .thenReturn(success(createRole(previousManagerRoleId, "product_manager", "产品经理")));

        ServiceException ex = assertThrows(ServiceException.class,
                () -> productMemberService.updateProductMember(productId, memberId, reqVO));

        assertEquals(ErrorCodeConstants.PRODUCT_MANAGER_TRANSFER_ROLE_INVALID.getCode(), ex.getCode());
        verify(userObjectRoleMapper).updateById(member);
        verify(productMapper, never()).updateById(any(ProductDO.class));
        verify(bizAuditLogMapper, never()).insert(any(BizAuditLogDO.class));
    }

    private ProductDO createProduct(Long productId, Long managerUserId) {
        ProductDO product = new ProductDO();
        product.setId(productId);
        product.setManagerUserId(managerUserId);
        product.setStatusCode("active");
        product.setName("测试产品");
        product.setCode("CNPD2026001");
        return product;
    }

    private UserObjectRoleDO createMember(Long memberId, Long productId, Long userId, Long roleId, Integer status) {
        UserObjectRoleDO member = new UserObjectRoleDO();
        member.setId(memberId);
        member.setObjectType("product");
        member.setObjectId(productId);
        member.setUserId(userId);
        member.setRoleId(roleId);
        member.setStatus(status);
        member.setJoinedTime(LocalDateTime.now());
        return member;
    }

    private ObjectRoleRespDTO createRole(Long roleId, String roleCode, String roleName) {
        ObjectRoleRespDTO role = new ObjectRoleRespDTO();
        role.setId(roleId);
        role.setCode(roleCode);
        role.setName(roleName);
        role.setScopeType("object");
        role.setObjectType("product");
        return role;
    }

    private AdminUserRespDTO createUser(String nickname) {
        AdminUserRespDTO user = new AdminUserRespDTO();
        user.setNickname(nickname);
        return user;
    }

}
