package tech.easyflow.admin.controller.job;

import com.easyagents.flow.core.chain.Parameter;
import org.mockito.MockedStatic;
import org.testng.Assert;
import org.testng.annotations.Test;
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.ai.service.WorkflowUsageAuthorizationService;
import tech.easyflow.common.constant.enums.EnumJobType;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.job.entity.SysJob;
import tech.easyflow.job.job.JobConstant;
import tech.easyflow.job.service.SysJobService;
import tech.easyflow.system.service.ResourceAccessService;

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

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

/**
 * {@link SysJobController} 工作流任务参数校验测试。
 */
public class SysJobControllerTest {

    /**
     * 验证缺少工作流必填参数时拒绝保存定时任务。
     */
    @Test
    public void shouldRejectWorkflowJobWhenRequiredParameterIsMissing() {
        BigInteger workflowId = BigInteger.valueOf(101);
        SysJobService jobService = mock(SysJobService.class);
        WorkflowService workflowService = mock(WorkflowService.class);
        WorkflowUsageAuthorizationService workflowAuthorizationService =
                mock(WorkflowUsageAuthorizationService.class);
        ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
        WorkflowRunningParameterResolver parameterResolver =
                mock(WorkflowRunningParameterResolver.class);
        Workflow workflow = new Workflow();
        workflow.setId(workflowId);
        workflow.setContent("{}");
        when(workflowAuthorizationService.requireUsableWorkflow(
                org.mockito.ArgumentMatchers.eq(workflowId),
                org.mockito.ArgumentMatchers.any(LoginAccount.class),
                org.mockito.ArgumentMatchers.anyString()))
                .thenReturn(workflow);
        Parameter requiredParameter = mock(Parameter.class);
        when(requiredParameter.isRequired()).thenReturn(true);
        when(requiredParameter.getName()).thenReturn("user_input");
        when(requiredParameter.getFormLabel()).thenReturn("用户问题");
        when(parameterResolver.resolveStartParameters(workflow.getContent()))
                .thenReturn(List.of(requiredParameter));
        SysJobController controller = new SysJobController(
                jobService,
                workflowService,
                workflowAuthorizationService,
                resourceAccessService,
                parameterResolver
        );
        SysJob job = new SysJob();
        job.setJobType(EnumJobType.TINY_FLOW.getCode());
        job.setJobParams(Map.of(
                JobConstant.WORKFLOW_KEY, workflowId.toString(),
                JobConstant.WORKFLOW_PARAMS_KEY, Map.of()
        ));
        LoginAccount account = new LoginAccount();
        account.setId(BigInteger.ONE);

        try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
            saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);

            BusinessException exception = Assert.expectThrows(
                    BusinessException.class,
                    () -> controller.onSaveOrUpdateBefore(job, true)
            );

            Assert.assertTrue(exception.getMessage().contains("用户问题"));
        }
    }

    /**
     * 验证部分更新省略任务类型时仍按数据库中的工作流任务类型完成引用校验。
     */
    @Test
    public void shouldValidateMergedWorkflowReferenceOnPartialUpdate() {
        BigInteger jobId = BigInteger.valueOf(201);
        BigInteger oldWorkflowId = BigInteger.valueOf(301);
        BigInteger newWorkflowId = BigInteger.valueOf(302);
        SysJobService jobService = mock(SysJobService.class);
        WorkflowService workflowService = mock(WorkflowService.class);
        WorkflowUsageAuthorizationService workflowAuthorizationService =
                mock(WorkflowUsageAuthorizationService.class);
        ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
        WorkflowRunningParameterResolver parameterResolver =
                mock(WorkflowRunningParameterResolver.class);

        SysJob existing = new SysJob();
        existing.setId(jobId);
        existing.setJobType(EnumJobType.TINY_FLOW.getCode());
        existing.setJobParams(Map.of(
                JobConstant.WORKFLOW_KEY, oldWorkflowId.toString(),
                JobConstant.WORKFLOW_PARAMS_KEY, Map.of()
        ));
        when(jobService.getById(jobId)).thenReturn(existing);
        when(workflowAuthorizationService.requireUsableWorkflow(
                org.mockito.ArgumentMatchers.eq(newWorkflowId),
                org.mockito.ArgumentMatchers.any(LoginAccount.class),
                org.mockito.ArgumentMatchers.anyString()))
                .thenThrow(new BusinessException("无权限运行所选工作流"));

        SysJob update = new SysJob();
        update.setId(jobId);
        update.setJobParams(Map.of(
                JobConstant.WORKFLOW_KEY, newWorkflowId.toString(),
                JobConstant.WORKFLOW_PARAMS_KEY, Map.of()
        ));
        LoginAccount account = new LoginAccount();
        account.setId(BigInteger.ONE);

        SysJobController controller = new SysJobController(
                jobService,
                workflowService,
                workflowAuthorizationService,
                resourceAccessService,
                parameterResolver
        );
        try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
            saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);

            BusinessException exception = Assert.expectThrows(
                    BusinessException.class,
                    () -> controller.onSaveOrUpdateBefore(update, false)
            );

            Assert.assertTrue(exception.getMessage().contains("无权限"));
            verify(workflowAuthorizationService).requireUsableWorkflow(
                    org.mockito.ArgumentMatchers.eq(newWorkflowId),
                    org.mockito.ArgumentMatchers.eq(account),
                    org.mockito.ArgumentMatchers.anyString());
        }
    }
}
