package tech.easyflow.agent.runtime;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import tech.easyflow.agent.entity.Agent;
import tech.easyflow.agent.entity.AgentToolBinding;
import tech.easyflow.agent.service.AgentService;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.chatlog.service.ChatSessionQueryService;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;

import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.List;

/**
 * {@link AgentRunService} 公共 API 租户边界测试。
 */
public class AgentRunServicePublicTest {

    /**
     * 验证 API Key 不能运行其他租户的 Agent。
     *
     * @throws Exception 注入测试依赖失败
     */
    @Test
    public void chatPublicShouldRejectCrossTenantAgent() throws Exception {
        BigInteger agentId = BigInteger.valueOf(1001);
        Agent agent = new Agent();
        agent.setId(agentId);
        agent.setTenantId(BigInteger.valueOf(2001));
        AgentService agentService = Mockito.mock(AgentService.class);
        Mockito.when(agentService.getById(agentId)).thenReturn(agent);
        AgentRunService service = new AgentRunService();
        setField(service, "agentService", agentService);
        AgentChatRequest request = new AgentChatRequest();
        request.setAgentId(agentId);
        request.setPrompt("hello");
        LoginAccount account = new LoginAccount();
        account.setId(BigInteger.valueOf(3001));
        account.setTenantId(BigInteger.valueOf(2002));

        BusinessException exception = Assert.assertThrows(
                BusinessException.class,
                () -> service.chatPublic(request, account)
        );

        Assert.assertEquals("Agent 不存在或不可用", exception.getMessage());
        Mockito.verify(agentService, Mockito.never()).getPublishedView(agentId);
    }

    /**
     * 公共 API 没有恢复入口时必须拒绝包含 HITL 工具的 Agent。
     *
     * @throws Exception 注入测试依赖失败
     */
    @Test
    public void chatPublicShouldRejectHitlTool() throws Exception {
        BigInteger agentId = BigInteger.valueOf(1001);
        BigInteger tenantId = BigInteger.valueOf(2001);
        Agent liveAgent = new Agent();
        liveAgent.setId(agentId);
        liveAgent.setTenantId(tenantId);
        liveAgent.setStatus(1);
        liveAgent.setPublishStatus(PublishStatus.PUBLISHED.getCode());
        AgentToolBinding binding = new AgentToolBinding();
        binding.setEnabled(true);
        binding.setHitlEnabled(true);
        Agent publishedAgent = new Agent();
        publishedAgent.setId(agentId);
        publishedAgent.setToolBindings(List.of(binding));
        AgentService agentService = Mockito.mock(AgentService.class);
        Mockito.when(agentService.getById(agentId)).thenReturn(liveAgent);
        Mockito.when(agentService.getPublishedView(agentId)).thenReturn(publishedAgent);
        AgentRunService service = new AgentRunService();
        setField(service, "agentService", agentService);
        setField(service, "chatSessionQueryService", Mockito.mock(ChatSessionQueryService.class));
        AgentChatRequest request = new AgentChatRequest();
        request.setAgentId(agentId);
        request.setPrompt("hello");
        LoginAccount account = new LoginAccount();
        account.setId(BigInteger.valueOf(3001));
        account.setTenantId(tenantId);

        BusinessException exception = Assert.assertThrows(
                BusinessException.class,
                () -> service.chatPublic(request, account)
        );

        Assert.assertEquals("公共 Agent API 暂不支持需要执行确认的工具", exception.getMessage());
    }

    /**
     * 写入被测对象私有字段。
     *
     * @param target 被测对象
     * @param fieldName 字段名
     * @param value 字段值
     * @throws Exception 字段不存在或不可访问
     */
    private void setField(Object target, String fieldName, Object value) throws Exception {
        Field field = target.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(target, value);
    }
}
