package tech.easyflow.admin.controller.ai;

import com.mybatisflex.core.query.QueryWrapper;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import org.testng.Assert;
import org.testng.annotations.Test;
import tech.easyflow.ai.entity.Mcp;
import tech.easyflow.ai.service.AgentResourceReferenceService;
import tech.easyflow.ai.service.McpService;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;

import java.math.BigInteger;
import java.util.Locale;

import static org.mockito.ArgumentMatchers.any;
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 McpController} 删除锁测试。
 */
public class McpControllerTest {

    /**
     * 验证 MCP 删除先锁定资源行，再执行删除。
     */
    @Test
    public void removeShouldLockMcpBeforeRemoval() {
        McpService mcpService = mock(McpService.class);
        AgentResourceReferenceService referenceService = mock(AgentResourceReferenceService.class);
        when(mcpService.getOne(any(QueryWrapper.class))).thenReturn(new Mcp());
        McpController controller = new McpController(mcpService);
        setField(controller, "agentResourceReferenceService", referenceService);
        LoginAccount loginAccount = new LoginAccount();
        loginAccount.setTenantId(BigInteger.ONE);

        try (MockedStatic<SaTokenUtil> login = mockStatic(SaTokenUtil.class)) {
            login.when(SaTokenUtil::getLoginAccount).thenReturn(loginAccount);
            controller.remove(BigInteger.TEN);
        }

        ArgumentCaptor<QueryWrapper> queryCaptor = ArgumentCaptor.forClass(QueryWrapper.class);
        verify(mcpService).getOne(queryCaptor.capture());
        Assert.assertTrue(
                queryCaptor.getValue().toSQL().toUpperCase(Locale.ROOT).contains("FOR UPDATE")
        );
        verify(referenceService).assertMcpUnused(BigInteger.TEN);
        verify(mcpService).removeMcp(BigInteger.TEN);
    }

    /**
     * 通过反射设置字段值。
     *
     * @param target 目标对象
     * @param fieldName 字段名
     * @param value 字段值
     */
    private static void setField(Object target, String fieldName, Object value) {
        try {
            java.lang.reflect.Field field = target.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(target, value);
        } catch (ReflectiveOperationException e) {
            throw new IllegalStateException("设置测试字段失败: " + fieldName, e);
        }
    }
}
