package tech.easyflow.ai.publish;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.plugin.workflow.binding.WorkflowPluginBindingService;
import tech.easyflow.ai.plugin.workflow.snapshot.WorkflowPluginSnapshotResolver;
import tech.easyflow.ai.service.ResourceOfflineImpactService;
import tech.easyflow.ai.service.AgentResourceReferenceService;
import tech.easyflow.ai.service.WorkflowScheduleReferenceProvider;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.ai.vo.OfflineImpactBindingVo;
import tech.easyflow.ai.vo.OfflineImpactCheckVo;
import tech.easyflow.approval.enums.ApprovalActionType;
import tech.easyflow.approval.service.ApprovalInstanceService;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.service.ResourceAccessService;

import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

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

/**
 * 工作流删除依赖校验测试。
 */
public class WorkflowApprovalSubjectHandlerTest {

    /**
     * 验证工作流被定时任务引用时不能删除。
     */
    @Test
    public void shouldRejectDeleteWhenScheduledJobReferencesWorkflow() {
        BigInteger workflowId = BigInteger.valueOf(101);
        ResourceOfflineImpactService offlineImpactService = mock(ResourceOfflineImpactService.class);
        OfflineImpactCheckVo impact = new OfflineImpactCheckVo();
        impact.setHasAgentBindings(false);
        when(offlineImpactService.checkWorkflowImpact(workflowId)).thenReturn(impact);
        WorkflowScheduleReferenceProvider scheduleReferenceProvider = ignored -> List.of(binding(201, "每日同步"));
        WorkflowApprovalSubjectHandler handler = new WorkflowApprovalSubjectHandler(
                mock(WorkflowService.class),
                mock(ResourceAccessService.class),
                mock(ApprovalInstanceService.class),
                offlineImpactService,
                mock(WorkflowPluginBindingService.class),
                mock(WorkflowPluginSnapshotResolver.class),
                mock(AgentResourceReferenceService.class),
                new ObjectMapper(),
                List.of(scheduleReferenceProvider)
        );
        Workflow workflow = new Workflow();
        workflow.setId(workflowId);

        try {
            handler.buildDeleteSnapshot(workflow, PublishStatus.OFFLINE);
            Assert.fail("工作流被定时任务引用时应阻止删除");
        } catch (BusinessException exception) {
            Assert.assertTrue(exception.getMessage().contains("每日同步"));
        }
    }

    /**
     * 验证审批等待期间新增定时任务引用后，真实删除动作会重新校验并阻止删除。
     */
    @Test
    public void shouldRecheckScheduledJobReferenceBeforeApprovedDelete() {
        BigInteger workflowId = BigInteger.valueOf(102);
        WorkflowService workflowService = mock(WorkflowService.class);
        ResourceOfflineImpactService offlineImpactService = mock(ResourceOfflineImpactService.class);
        OfflineImpactCheckVo impact = new OfflineImpactCheckVo();
        impact.setHasAgentBindings(false);
        when(offlineImpactService.checkWorkflowImpact(workflowId)).thenReturn(impact);
        AtomicInteger referenceChecks = new AtomicInteger();
        WorkflowScheduleReferenceProvider scheduleReferenceProvider = ignored ->
                referenceChecks.incrementAndGet() == 1
                        ? List.of()
                        : List.of(binding(202, "审批期间新增任务"));
        WorkflowApprovalSubjectHandler handler = new WorkflowApprovalSubjectHandler(
                workflowService,
                mock(ResourceAccessService.class),
                mock(ApprovalInstanceService.class),
                offlineImpactService,
                mock(WorkflowPluginBindingService.class),
                mock(WorkflowPluginSnapshotResolver.class),
                mock(AgentResourceReferenceService.class),
                new ObjectMapper(),
                List.of(scheduleReferenceProvider)
        );
        Workflow workflow = new Workflow();
        workflow.setId(workflowId);
        workflow.setPublishStatus(PublishStatus.OFFLINE.getCode());
        when(workflowService.getById(workflowId)).thenReturn(workflow);

        handler.buildDeleteSnapshot(workflow, PublishStatus.OFFLINE);

        try {
            handler.applyApprovedAction(
                    ApprovalActionType.DELETE.getCode(),
                    workflowId,
                    Map.of(),
                    BigInteger.ONE
            );
            Assert.fail("审批期间新增定时任务引用后应阻止删除");
        } catch (BusinessException exception) {
            Assert.assertTrue(exception.getMessage().contains("审批期间新增任务"));
        }

        verify(workflowService, never()).removeById(workflowId);
        Assert.assertEquals(2, referenceChecks.get());
    }

    /**
     * 创建定时任务引用摘要。
     *
     * @param id 定时任务 ID
     * @param title 定时任务名称
     * @return 引用摘要
     */
    private OfflineImpactBindingVo binding(long id, String title) {
        OfflineImpactBindingVo binding = new OfflineImpactBindingVo();
        binding.setId(BigInteger.valueOf(id));
        binding.setTitle(title);
        return binding;
    }
}
