package tech.easyflow.ai.service;

import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.common.constant.enums.EnumDataStatus;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.service.ResourceAccessService;

import java.math.BigInteger;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * {@link WorkflowUsageAuthorizationService} 工作流使用权限校验测试。
 */
public class WorkflowUsageAuthorizationServiceTest {

    /**
     * 验证禁用工作流即使资源权限允许也不能被使用。
     */
    @Test
    public void shouldRejectDisabledWorkflow() {
        BigInteger workflowId = BigInteger.valueOf(101);
        WorkflowService workflowService = mock(WorkflowService.class);
        ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
        Workflow workflow = workflow(workflowId, BigInteger.TEN, EnumDataStatus.UNAVAILABLE.getCode());
        LoginAccount account = account(BigInteger.ONE, BigInteger.TEN);
        when(workflowService.getById(workflowId)).thenReturn(workflow);
        when(resourceAccessService.canAccess(
                account,
                CategoryResourceType.WORKFLOW,
                workflow,
                ResourceAction.USE)).thenReturn(true);
        WorkflowUsageAuthorizationService service =
                new WorkflowUsageAuthorizationService(workflowService, resourceAccessService);

        BusinessException exception = Assert.assertThrows(
                BusinessException.class,
                () -> service.requireUsableWorkflow(workflowId, account, "工作流不可用")
        );

        Assert.assertEquals(exception.getMessage(), "工作流不可用");
    }

    /**
     * 验证工作流与账号租户不一致时拒绝使用。
     */
    @Test
    public void shouldRejectCrossTenantWorkflow() {
        BigInteger workflowId = BigInteger.valueOf(102);
        WorkflowService workflowService = mock(WorkflowService.class);
        ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
        Workflow workflow = workflow(
                workflowId,
                BigInteger.valueOf(20),
                EnumDataStatus.AVAILABLE.getCode());
        LoginAccount account = account(BigInteger.ONE, BigInteger.TEN);
        when(workflowService.getById(workflowId)).thenReturn(workflow);
        WorkflowUsageAuthorizationService service =
                new WorkflowUsageAuthorizationService(workflowService, resourceAccessService);

        Assert.assertThrows(
                BusinessException.class,
                () -> service.requireUsableWorkflow(workflowId, account, "工作流不可用")
        );
    }

    /**
     * 验证启用、同租户且具有使用权限的工作流可以返回。
     */
    @Test
    public void shouldReturnUsableWorkflow() {
        BigInteger workflowId = BigInteger.valueOf(103);
        WorkflowService workflowService = mock(WorkflowService.class);
        ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
        Workflow workflow = workflow(
                workflowId,
                BigInteger.TEN,
                EnumDataStatus.AVAILABLE.getCode());
        LoginAccount account = account(BigInteger.ONE, BigInteger.TEN);
        when(workflowService.getById(workflowId)).thenReturn(workflow);
        when(resourceAccessService.canAccess(
                account,
                CategoryResourceType.WORKFLOW,
                workflow,
                ResourceAction.USE)).thenReturn(true);
        WorkflowUsageAuthorizationService service =
                new WorkflowUsageAuthorizationService(workflowService, resourceAccessService);

        Workflow result = service.requireUsableWorkflow(workflowId, account, "工作流不可用");

        Assert.assertSame(result, workflow);
    }

    /**
     * 创建工作流测试数据。
     *
     * @param id 工作流 ID
     * @param tenantId 租户 ID
     * @param status 工作流状态
     * @return 工作流
     */
    private Workflow workflow(BigInteger id, BigInteger tenantId, Integer status) {
        Workflow workflow = new Workflow();
        workflow.setId(id);
        workflow.setTenantId(tenantId);
        workflow.setStatus(status);
        return workflow;
    }

    /**
     * 创建登录账号测试数据。
     *
     * @param id 账号 ID
     * @param tenantId 租户 ID
     * @return 登录账号
     */
    private LoginAccount account(BigInteger id, BigInteger tenantId) {
        LoginAccount account = new LoginAccount();
        account.setId(id);
        account.setTenantId(tenantId);
        return account;
    }
}
