package tech.easyflow.publicapi.controller;

import com.easyagents.flow.core.chain.ChainStatus;
import com.easyagents.flow.core.chain.NodeStatus;
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.entity.WorkflowExecResult;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.service.WorkflowApiPermissionService;
import tech.easyflow.ai.service.WorkflowExecResultService;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.ai.utils.WorkFlowUtil;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.publicapi.dto.PublicWorkflowChainStatus;
import tech.easyflow.publicapi.dto.PublicWorkflowExecutionStatus;
import tech.easyflow.publicapi.service.PublicWorkflowStatusSanitizer;
import tech.easyflow.system.entity.SysApiKey;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * {@link PublicWorkflowController} 状态查询与恢复行为测试。
 */
public class PublicWorkflowControllerBehaviorTest {

    private static final String EXECUTE_ID = "execute-1";

    private PublicWorkflowController controller;
    private ChainExecutor chainExecutor;
    private TinyFlowService tinyFlowService;
    private HttpServletRequest request;

    /**
     * 创建通过 API Key 执行归属校验的控制器测试夹具。
     */
    @Before
    public void setUp() {
        controller = new PublicWorkflowController();
        chainExecutor = Mockito.mock(ChainExecutor.class);
        tinyFlowService = Mockito.mock(TinyFlowService.class);
        WorkflowApiPermissionService permissionService =
                Mockito.mock(WorkflowApiPermissionService.class);
        WorkflowExecResultService execResultService =
                Mockito.mock(WorkflowExecResultService.class);
        WorkflowService workflowService =
                Mockito.mock(WorkflowService.class);
        request = Mockito.mock(HttpServletRequest.class);

        SysApiKey apiKey = new SysApiKey();
        apiKey.setId(BigInteger.TEN);
        when(request.getHeader("ApiKey")).thenReturn("api-key");
        when(request.getRequestURI()).thenReturn(
                "/public-api/workflow/getChainStatus");
        when(permissionService.assertWorkflowApi(any(), anyString()))
                .thenReturn(apiKey);
        when(execResultService.getByExecKey(EXECUTE_ID))
                .thenReturn(executionRecord());
        when(workflowService.getById(BigInteger.ONE))
                .thenReturn(publishedWorkflow());

        ReflectionTestUtils.setField(
                controller,
                "chainExecutor",
                chainExecutor);
        ReflectionTestUtils.setField(
                controller,
                "tinyFlowService",
                tinyFlowService);
        ReflectionTestUtils.setField(
                controller,
                "workflowApiPermissionService",
                permissionService);
        ReflectionTestUtils.setField(
                controller,
                "workflowExecResultService",
                execResultService);
        ReflectionTestUtils.setField(
                controller,
                "workflowService",
                workflowService);
        ReflectionTestUtils.setField(
                controller,
                "publicWorkflowStatusSanitizer",
                new PublicWorkflowStatusSanitizer());
    }

    /**
     * 验证非暂停状态恢复返回稳定冲突错误，且不会调用旧的无条件恢复入口。
     */
    @Test
    public void resumeShouldRejectNonSuspendedExecution() {
        when(request.getRequestURI()).thenReturn(
                "/public-api/workflow/resume");
        when(chainExecutor.resumeAsyncIfSuspended(
                EXECUTE_ID,
                Map.of("approved", true)))
                .thenReturn(false);

        try {
            controller.resume(
                    EXECUTE_ID,
                    Map.of("approved", true),
                    request);
            Assert.fail("非暂停状态必须拒绝恢复");
        } catch (BusinessException exception) {
            Assert.assertEquals(409, exception.getHttpStatus());
            Assert.assertEquals(40901, exception.getErrorCode());
        }

        verify(chainExecutor).resumeAsyncIfSuspended(
                EXECUTE_ID,
                Map.of("approved", true));
    }

    /**
     * 验证状态查询使用定义快照补齐节点名称并返回可读枚举。
     */
    @Test
    public void statusShouldEnrichNodeNameAndReadableEnum() {
        ChainInfo chainInfo = new ChainInfo();
        chainInfo.setExecuteId(EXECUTE_ID);
        chainInfo.setStatus(ChainStatus.RUNNING.getValue());
        NodeInfo node = new NodeInfo();
        node.setNodeId("node-1");
        node.setNodeName("文档解析");
        node.setStatus(NodeStatus.RUNNING.getValue());
        chainInfo.setNodes(Map.of("node-1", node));
        when(tinyFlowService.getChainStatus(
                EXECUTE_ID,
                List.of(node)))
                .thenReturn(chainInfo);

        Result<PublicWorkflowChainStatus> result =
                controller.getChainStatus(
                        EXECUTE_ID,
                        List.of(node),
                        request);

        Assert.assertEquals(
                PublicWorkflowExecutionStatus.RUNNING,
                result.getData().status());
        Assert.assertFalse(result.getData().terminal());
        Assert.assertEquals(
                "文档解析",
                result.getData().nodes().get("node-1").nodeName());
    }

    /**
     * 创建属于当前 API Key 的执行记录。
     *
     * @return 执行记录
     */
    private WorkflowExecResult executionRecord() {
        WorkflowExecResult result = new WorkflowExecResult();
        result.setExecKey(EXECUTE_ID);
        result.setWorkflowId(BigInteger.ONE);
        result.setCreatedKey(WorkFlowUtil.API_KEY);
        result.setCreatedBy(BigInteger.TEN.toString());
        return result;
    }

    /**
     * 创建可恢复校验使用的已发布工作流。
     *
     * @return 已发布工作流
     */
    private Workflow publishedWorkflow() {
        Workflow workflow = new Workflow();
        workflow.setId(BigInteger.ONE);
        workflow.setPublishStatus(PublishStatus.PUBLISHED.getCode());
        workflow.setPublishedSnapshotJson(Map.of("nodes", List.of()));
        return workflow;
    }
}
