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

import com.njcn.rdms.framework.common.exception.ServiceException;
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.status.ObjectStatusModelDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusTransitionDO;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;

import java.util.List;

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.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;

class ProjectTaskStatusViewServiceTest extends BaseMockitoUnitTest {

    @InjectMocks
    private ProjectTaskStatusViewService projectTaskStatusViewService;
    @Mock
    private ObjectStatusModelMapper objectStatusModelMapper;
    @Mock
    private ObjectStatusTransitionMapper objectStatusTransitionMapper;

    @Test
    void getLifecycle_whenLoginUserIsOwner_shouldReturnOwnerOnlyActions() {
        Long ownerId = 3001L;
        ObjectStatusModelDO statusModel = createStatusModel();
        ObjectStatusTransitionDO complete = createTransition("complete", "完成");
        ObjectStatusTransitionDO pause = createTransition("pause", "暂停");
        when(objectStatusModelMapper.selectByObjectTypeAndStatusCodeEnabled("task", "active")).thenReturn(statusModel);
        when(objectStatusTransitionMapper.selectListByObjectTypeAndFromStatus("task", "active"))
                .thenReturn(List.of(complete, pause));

        try (MockedStatic<SecurityFrameworkUtils> mocked = mockStatic(SecurityFrameworkUtils.class)) {
            mocked.when(SecurityFrameworkUtils::getLoginUserId).thenReturn(ownerId);

            ProjectTaskStatusViewService.ProjectTaskLifecycleView view =
                    projectTaskStatusViewService.getLifecycle("active", ownerId);

            assertEquals("进行中", view.statusName());
            assertFalse(view.terminal());
            assertTrue(view.allowEdit());
            assertEquals(2, view.availableActions().size());
            assertEquals("complete", view.availableActions().get(0).getActionCode());
            assertEquals("完成", view.availableActions().get(0).getActionName());
        }
    }

    @Test
    void getLifecycle_whenLoginUserNotOwner_shouldFilterOwnerOnlyActions() {
        Long ownerId = 3001L;
        Long otherUserId = 3002L;
        ObjectStatusModelDO statusModel = createStatusModel();
        ObjectStatusTransitionDO complete = createTransition("complete", "完成");
        ObjectStatusTransitionDO pause = createTransition("pause", "暂停");
        when(objectStatusModelMapper.selectByObjectTypeAndStatusCodeEnabled("task", "active")).thenReturn(statusModel);
        when(objectStatusTransitionMapper.selectListByObjectTypeAndFromStatus("task", "active"))
                .thenReturn(List.of(complete, pause));

        try (MockedStatic<SecurityFrameworkUtils> mocked = mockStatic(SecurityFrameworkUtils.class)) {
            mocked.when(SecurityFrameworkUtils::getLoginUserId).thenReturn(otherUserId);

            ProjectTaskStatusViewService.ProjectTaskLifecycleView view =
                    projectTaskStatusViewService.getLifecycle("active", ownerId);

            assertTrue(view.availableActions().isEmpty());
        }
    }

    @Test
    void getLifecycle_shouldExcludeAutoStartAction() {
        Long ownerId = 3001L;
        ObjectStatusModelDO statusModel = new ObjectStatusModelDO();
        statusModel.setObjectType("task");
        statusModel.setStatusCode("pending");
        statusModel.setStatusName("待开始");
        statusModel.setTerminalFlag(false);
        statusModel.setAllowEdit(true);
        ObjectStatusTransitionDO autoStart = createTransition("auto_start", "开始推进");
        when(objectStatusModelMapper.selectByObjectTypeAndStatusCodeEnabled("task", "pending")).thenReturn(statusModel);
        when(objectStatusTransitionMapper.selectListByObjectTypeAndFromStatus("task", "pending"))
                .thenReturn(List.of(autoStart));

        try (MockedStatic<SecurityFrameworkUtils> mocked = mockStatic(SecurityFrameworkUtils.class)) {
            mocked.when(SecurityFrameworkUtils::getLoginUserId).thenReturn(ownerId);

            ProjectTaskStatusViewService.ProjectTaskLifecycleView view =
                    projectTaskStatusViewService.getLifecycle("pending", ownerId);

            assertTrue(view.availableActions().isEmpty());
        }
    }

    @Test
    void getLifecycle_whenStatusModelMissing_shouldThrow() {
        when(objectStatusModelMapper.selectByObjectTypeAndStatusCodeEnabled("task", "missing")).thenReturn(null);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> projectTaskStatusViewService.getLifecycle("missing", 3001L));

        assertEquals(ErrorCodeConstants.PROJECT_TASK_STATUS_MODEL_NOT_EXISTS_OR_DISABLED.getCode(), ex.getCode());
    }

    private ObjectStatusModelDO createStatusModel() {
        ObjectStatusModelDO statusModel = new ObjectStatusModelDO();
        statusModel.setObjectType("task");
        statusModel.setStatusCode("active");
        statusModel.setStatusName("进行中");
        statusModel.setTerminalFlag(false);
        statusModel.setAllowEdit(true);
        return statusModel;
    }

    private ObjectStatusTransitionDO createTransition(String actionCode, String actionName) {
        ObjectStatusTransitionDO transition = new ObjectStatusTransitionDO();
        transition.setActionCode(actionCode);
        transition.setActionName(actionName);
        return transition;
    }

}
