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

import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.ProjectTaskDO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.TaskAssigneeDO;
import com.njcn.rdms.module.project.dal.mysql.project.ProjectMapper;
import com.njcn.rdms.module.project.dal.mysql.project.task.TaskAssigneeMapper;
import com.njcn.rdms.module.project.framework.notify.NotifyJumpConstants;
import com.njcn.rdms.module.project.framework.notify.NotifySendEvent;
import com.njcn.rdms.module.project.framework.notify.NotifyTemplateCodeConstants;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.springframework.context.ApplicationEventPublisher;

import java.util.Arrays;
import java.util.List;

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

/**
 * {@link ProjectTaskServiceImpl} 的单元测试 —— 任务指派站内信埋点。
 * 仅验证埋点方法 {@code publishTaskAssignedNotify} 的收件人/参数组织与事件发布；
 * createTask 端到端正确性由运行态联调验证。
 */
class ProjectTaskServiceImplTest extends BaseMockitoUnitTest {

    @InjectMocks
    private ProjectTaskServiceImpl projectTaskService;

    @Mock
    private ProjectMapper projectMapper;
    @Mock
    private TaskAssigneeMapper taskAssigneeMapper;
    @Mock
    private ApplicationEventPublisher applicationEventPublisher;

    @Test
    void testPublishTaskAssignedNotify_recipientsAndParams() {
        ProjectTaskDO task = new ProjectTaskDO();
        task.setId(1000L);
        task.setTaskTitle("联调任务");
        // 活跃协办人 2L、3L
        TaskAssigneeDO a2 = new TaskAssigneeDO();
        a2.setUserId(2L);
        TaskAssigneeDO a3 = new TaskAssigneeDO();
        a3.setUserId(3L);
        when(taskAssigneeMapper.selectActiveListByTaskId(1000L)).thenReturn(Arrays.asList(a2, a3));
        ProjectDO project = new ProjectDO();
        project.setProjectName("演示项目");
        when(projectMapper.selectById(50L)).thenReturn(project);

        projectTaskService.publishTaskAssignedNotify(50L, task, 1L);

        ArgumentCaptor<NotifySendEvent> captor = ArgumentCaptor.forClass(NotifySendEvent.class);
        verify(applicationEventPublisher).publishEvent(captor.capture());
        NotifySendEvent event = captor.getValue();
        assertEquals(NotifyJumpConstants.JUMP_TYPE_TASK,
                event.getParams().get(NotifyJumpConstants.PARAM_JUMP_TYPE));
        assertEquals("50", event.getParams().get(NotifyJumpConstants.PARAM_PROJECT_ID));
        assertEquals(NotifyTemplateCodeConstants.TASK_ASSIGNED, event.getTemplateCode());
        assertTrue(event.getUserIds().contains(1L)); // 负责人
        assertTrue(event.getUserIds().contains(2L)); // 协办人
        assertTrue(event.getUserIds().contains(3L)); // 协办人
        assertEquals("演示项目", event.getParams().get("projectName"));
        assertEquals("联调任务", event.getParams().get("taskName"));
    }

    /**
     * 事件须携带操作人（登录用户）id，供监听器统一从收件人里排除操作人自己。
     */
    @Test
    void publishTaskAssignedNotify_carriesOperator() {
        try (MockedStatic<SecurityFrameworkUtils> mocked = mockStatic(SecurityFrameworkUtils.class)) {
            mocked.when(SecurityFrameworkUtils::getLoginUserId).thenReturn(99L);
            ProjectTaskDO task = new ProjectTaskDO();
            task.setId(1L);
            task.setTaskTitle("接口联调");
            when(taskAssigneeMapper.selectActiveListByTaskId(1L)).thenReturn(List.of());
            when(projectMapper.selectById(any())).thenReturn(null);

            ArgumentCaptor<NotifySendEvent> captor = ArgumentCaptor.forClass(NotifySendEvent.class);
            projectTaskService.publishTaskAssignedNotify(10L, task, 5L);
            verify(applicationEventPublisher).publishEvent(captor.capture());
            assertEquals(99L, captor.getValue().getOperatorUserId());
        }
    }
}
