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

import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskLifecycleActionRespVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.mytask.MyTaskPageReqVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.mytask.MyTaskRespVO;
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.mysql.project.ProjectMapper;
import com.njcn.rdms.module.project.dal.mysql.project.execution.ProjectExecutionMapper;
import com.njcn.rdms.module.project.dal.mysql.project.task.ProjectTaskMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

import static java.util.Collections.emptyList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;

class MyTaskServiceImplTest extends BaseMockitoUnitTest {

    @InjectMocks
    private MyTaskServiceImpl myTaskService;
    @Mock
    private ProjectTaskMapper projectTaskMapper;
    @Mock
    private ProjectMapper projectMapper;
    @Mock
    private ProjectExecutionMapper projectExecutionMapper;
    @Mock
    private ObjectStatusModelMapper objectStatusModelMapper;
    @Mock
    private ProjectTaskStatusViewService projectTaskStatusViewService;

    private ProjectTaskDO task(Long id, Long ownerId, Long projectId) {
        ProjectTaskDO t = new ProjectTaskDO();
        t.setId(id);
        t.setOwnerId(ownerId);
        t.setProjectId(projectId);
        t.setStatusCode("active");
        return t;
    }

    private ProjectTaskLifecycleActionRespVO action(String actionCode, String actionName, Boolean needReason) {
        ProjectTaskLifecycleActionRespVO action = new ProjectTaskLifecycleActionRespVO();
        action.setActionCode(actionCode);
        action.setActionName(actionName);
        action.setNeedReason(needReason);
        return action;
    }

    @Test
    void emptyWhenNoTasks() {
        try (MockedStatic<SecurityFrameworkUtils> mock = mockStatic(SecurityFrameworkUtils.class)) {
            mock.when(SecurityFrameworkUtils::getLoginUserId).thenReturn(100L);
            when(objectStatusModelMapper.selectTerminalStatusCodesByObjectTypeEnabled(anyString()))
                    .thenReturn(List.of("completed", "cancelled"));
            when(projectTaskMapper.selectMyUnfinishedInvolvedList(eq(100L), any(), anyCollection()))
                    .thenReturn(emptyList());
            PageResult<MyTaskRespVO> result = myTaskService.getMyTaskPage(new MyTaskPageReqVO());
            assertEquals(0L, result.getTotal());
        }
    }

    @Test
    void myRole_ownerWinsOverCollaborator() {
        try (MockedStatic<SecurityFrameworkUtils> mock = mockStatic(SecurityFrameworkUtils.class)) {
            mock.when(SecurityFrameworkUtils::getLoginUserId).thenReturn(100L);
            when(objectStatusModelMapper.selectTerminalStatusCodesByObjectTypeEnabled(anyString()))
                    .thenReturn(List.of("completed", "cancelled"));
            // 任务1：我是 owner；任务2：owner 是别人（我只能是协办，SQL 才会返回它）
            when(projectTaskMapper.selectMyUnfinishedInvolvedList(eq(100L), any(), anyCollection()))
                    .thenReturn(List.of(task(1L, 100L, 10L), task(2L, 200L, 10L)));
            when(projectTaskStatusViewService.getLifecycleMap(any())).thenReturn(Map.of());
            ProjectDO project = new ProjectDO();
            project.setId(10L);
            project.setProjectName("收银台 V3");
            when(projectMapper.selectBatchIds(anyCollection())).thenReturn(List.of(project));
            PageResult<MyTaskRespVO> result = myTaskService.getMyTaskPage(new MyTaskPageReqVO());
            assertEquals(2L, result.getTotal());
            assertEquals("owner", result.getList().get(0).getMyRole());
            assertEquals("collaborator", result.getList().get(1).getMyRole());
            assertEquals("收银台 V3", result.getList().get(0).getProjectName());
        }
    }

    @Test
    void getMyTaskPage_shouldReturnProgressLifecycleAndParentTaskFields() {
        try (MockedStatic<SecurityFrameworkUtils> mock = mockStatic(SecurityFrameworkUtils.class)) {
            mock.when(SecurityFrameworkUtils::getLoginUserId).thenReturn(100L);
            when(objectStatusModelMapper.selectTerminalStatusCodesByObjectTypeEnabled(anyString()))
                    .thenReturn(List.of("completed", "cancelled"));

            ProjectTaskDO ownerTask = task(1L, 100L, 10L);
            ownerTask.setProgressRate(new BigDecimal("100.00"));
            ProjectTaskDO collaboratorTask = task(2L, 200L, 10L);
            collaboratorTask.setParentTaskId(1L);
            collaboratorTask.setProgressRate(null);
            when(projectTaskMapper.selectMyUnfinishedInvolvedList(eq(100L), any(), anyCollection()))
                    .thenReturn(List.of(ownerTask, collaboratorTask));
            when(projectTaskStatusViewService.getLifecycleMap(any())).thenReturn(Map.of(
                    1L, new ProjectTaskStatusViewService.ProjectTaskLifecycleView("进行中", false, true,
                            List.of(action("pause", "暂停", true), action("complete", "完成", false))),
                    2L, new ProjectTaskStatusViewService.ProjectTaskLifecycleView("进行中", false, true,
                            emptyList())));

            PageResult<MyTaskRespVO> result = myTaskService.getMyTaskPage(new MyTaskPageReqVO());

            MyTaskRespVO owner = result.getList().get(0);
            assertEquals(new BigDecimal("100.00"), owner.getProgressRate());
            assertFalse(owner.getTerminal());
            assertEquals(true, owner.getAllowEdit());
            assertNull(owner.getParentTaskId());
            assertEquals(List.of("pause", "complete"), owner.getAvailableActions().stream()
                    .map(action -> action.getActionCode())
                    .toList());
            assertEquals(List.of(true, false), owner.getAvailableActions().stream()
                    .map(action -> action.getNeedReason())
                    .toList());

            MyTaskRespVO collaborator = result.getList().get(1);
            assertEquals(BigDecimal.ZERO, collaborator.getProgressRate());
            assertEquals(1L, collaborator.getParentTaskId());
            assertEquals(emptyList(), collaborator.getAvailableActions());
        }
    }

}
