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

import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.json.JsonUtils;
import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
import com.njcn.rdms.module.project.controller.admin.product.vo.activity.ProductActivityPageReqVO;
import com.njcn.rdms.module.project.controller.admin.product.vo.activity.ProductActivityRespVO;
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.ProductStatusLogDO;
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.ProductStatusLogMapper;
import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
import org.junit.jupiter.api.Test;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.mockito.InjectMocks;
import org.mockito.Mock;

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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anySet;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class ProductActivityQueryServiceTest extends BaseMockitoUnitTest {

    @InjectMocks
    private ProductActivityQueryService productActivityQueryService;
    @Mock
    private ProductStatusLogMapper productStatusLogMapper;
    @Mock
    private BizAuditLogMapper bizAuditLogMapper;
    @Mock
    private UserObjectRoleMapper userObjectRoleMapper;
    @Mock
    private CacheManager cacheManager;
    @Mock
    private Cache roleNameCache;
    @Mock
    private ObjectPermissionApi objectPermissionApi;

    @Test
    void getProductActivities_shouldMergeStatusProductAndMemberActivities() {
        Long productId = 1001L;
        ProductActivityPageReqVO reqVO = new ProductActivityPageReqVO();
        reqVO.setPageNo(1);
        reqVO.setPageSize(10);

        ProductStatusLogDO statusLog = new ProductStatusLogDO();
        statusLog.setId(11L);
        statusLog.setProductId(productId);
        statusLog.setActionType("pause");
        statusLog.setOperatorName("张三");
        statusLog.setReason("资源不足");
        statusLog.setCreateTime(LocalDateTime.of(2026, 4, 21, 10, 0, 0));

        BizAuditLogDO productAudit = new BizAuditLogDO();
        productAudit.setId(22L);
        productAudit.setBizType("product");
        productAudit.setBizId(productId);
        productAudit.setActionType("update");
        productAudit.setOperatorName("李四");
        productAudit.setCreateTime(LocalDateTime.of(2026, 4, 21, 11, 0, 0));

        BizAuditLogDO memberAudit = new BizAuditLogDO();
        memberAudit.setId(33L);
        memberAudit.setBizType("rdms_user_object_role");
        memberAudit.setBizId(9001L);
        memberAudit.setActionType("add_member");
        memberAudit.setOperatorName("王五");
        memberAudit.setCreateTime(LocalDateTime.of(2026, 4, 21, 12, 0, 0));

        UserObjectRoleDO member = new UserObjectRoleDO();
        member.setId(9001L);
        member.setObjectType("product");
        member.setObjectId(productId);

        when(productStatusLogMapper.selectListByProductId(productId, null, null))
                .thenReturn(List.of(statusLog));
        when(bizAuditLogMapper.selectListByBiz("product", productId, null, null))
                .thenReturn(List.of(productAudit));
        when(bizAuditLogMapper.selectListByBizType("rdms_user_object_role", null, null))
                .thenReturn(List.of(memberAudit));
        when(userObjectRoleMapper.selectListByIdsAndObject(List.of(9001L), "product", productId))
                .thenReturn(List.of(member));

        PageResult<ProductActivityRespVO> result = productActivityQueryService.getProductActivities(productId, reqVO);

        assertEquals(3L, result.getTotal());
        assertEquals("member", result.getList().get(0).getType());
        assertEquals("product", result.getList().get(1).getType());
        assertEquals("status", result.getList().get(2).getType());
    }

    @Test
    void getProductActivities_shouldIgnoreOrphanMemberAuditAndFilterByType() {
        Long productId = 1002L;
        ProductActivityPageReqVO reqVO = new ProductActivityPageReqVO();
        reqVO.setPageNo(1);
        reqVO.setPageSize(10);
        reqVO.setActivityType("member");

        BizAuditLogDO orphanMemberAudit = new BizAuditLogDO();
        orphanMemberAudit.setId(44L);
        orphanMemberAudit.setBizType("rdms_user_object_role");
        orphanMemberAudit.setBizId(9900L);
        orphanMemberAudit.setActionType("remove_member");
        orphanMemberAudit.setCreateTime(LocalDateTime.of(2026, 4, 21, 9, 0, 0));

        when(bizAuditLogMapper.selectListByBizType("rdms_user_object_role", null, null))
                .thenReturn(List.of(orphanMemberAudit));
        when(userObjectRoleMapper.selectListByIdsAndObject(List.of(9900L), "product", productId))
                .thenReturn(List.of());

        PageResult<ProductActivityRespVO> result = productActivityQueryService.getProductActivities(productId, reqVO);

        assertEquals(0L, result.getTotal());
        assertEquals(0, result.getList().size());
    }

    @Test
    void getProductActivities_shouldAppendRoleNameToMemberDetails() {
        Long productId = 1003L;
        ProductActivityPageReqVO reqVO = new ProductActivityPageReqVO();
        reqVO.setPageNo(1);
        reqVO.setPageSize(10);
        reqVO.setActivityType("member");

        BizAuditLogDO memberAudit = new BizAuditLogDO();
        memberAudit.setId(55L);
        memberAudit.setBizType("rdms_user_object_role");
        memberAudit.setBizId(9002L);
        memberAudit.setActionType("update_member");
        memberAudit.setFieldChanges("{\"roleId\":{\"before\":3201,\"after\":3202}}");
        memberAudit.setCreateTime(LocalDateTime.of(2026, 4, 21, 13, 0, 0));

        UserObjectRoleDO member = new UserObjectRoleDO();
        member.setId(9002L);
        member.setObjectType("product");
        member.setObjectId(productId);

        when(bizAuditLogMapper.selectListByBizType("rdms_user_object_role", null, null))
                .thenReturn(List.of(memberAudit));
        when(userObjectRoleMapper.selectListByIdsAndObject(List.of(9002L), "product", productId))
                .thenReturn(List.of(member));
        when(cacheManager.getCache("project_activity_role_name#10m")).thenReturn(roleNameCache);
        when(roleNameCache.get(3201L, String.class)).thenReturn("产品经理");
        when(roleNameCache.get(3202L, String.class)).thenReturn("产品成员");

        PageResult<ProductActivityRespVO> result = productActivityQueryService.getProductActivities(productId, reqVO);

        assertEquals("产品经理", JsonUtils.parseTree(result.getList().get(0).getDetails())
                .path("roleName").path("before").asText());
        assertEquals("产品成员", JsonUtils.parseTree(result.getList().get(0).getDetails())
                .path("roleName").path("after").asText());
        verify(objectPermissionApi, never()).getObjectRoleMap(anySet(), any(), any());
    }

    @Test
    void getProductActivities_shouldLoadAndCacheRoleNameWhenCacheMiss() {
        Long productId = 1004L;
        ProductActivityPageReqVO reqVO = new ProductActivityPageReqVO();
        reqVO.setPageNo(1);
        reqVO.setPageSize(10);
        reqVO.setActivityType("member");

        BizAuditLogDO memberAudit = new BizAuditLogDO();
        memberAudit.setId(66L);
        memberAudit.setBizType("rdms_user_object_role");
        memberAudit.setBizId(9003L);
        memberAudit.setActionType("add_member");
        memberAudit.setFieldChanges("{\"roleId\":{\"before\":null,\"after\":3203}}");
        memberAudit.setCreateTime(LocalDateTime.of(2026, 4, 21, 14, 0, 0));

        UserObjectRoleDO member = new UserObjectRoleDO();
        member.setId(9003L);
        member.setObjectType("product");
        member.setObjectId(productId);

        when(bizAuditLogMapper.selectListByBizType("rdms_user_object_role", null, null))
                .thenReturn(List.of(memberAudit));
        when(userObjectRoleMapper.selectListByIdsAndObject(List.of(9003L), "product", productId))
                .thenReturn(List.of(member));
        when(cacheManager.getCache("project_activity_role_name#10m")).thenReturn(roleNameCache);
        when(roleNameCache.get(3203L, String.class)).thenReturn(null);
        when(objectPermissionApi.getObjectRoleMap(java.util.Set.of(3203L), "object", "product"))
                .thenReturn(Map.of(3203L, buildRole(3203L, "观察者")));

        PageResult<ProductActivityRespVO> result = productActivityQueryService.getProductActivities(productId, reqVO);

        assertEquals("观察者", JsonUtils.parseTree(result.getList().get(0).getDetails())
                .path("roleName").path("after").asText());
        verify(roleNameCache).put(3203L, "观察者");
    }

    private ObjectRoleRespDTO buildRole(Long id, String name) {
        ObjectRoleRespDTO role = new ObjectRoleRespDTO();
        role.setId(id);
        role.setName(name);
        role.setScopeType("object");
        role.setObjectType("product");
        return role;
    }

}
