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.Plugin;
import tech.easyflow.ai.entity.PluginItem;
import tech.easyflow.ai.service.AgentResourceReferenceService;
import tech.easyflow.ai.service.PluginItemService;
import tech.easyflow.ai.service.PluginService;
import tech.easyflow.ai.service.PluginVisibilityService;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;

import java.math.BigInteger;
import java.util.List;
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 PluginItemController} 删除锁测试。
 */
public class PluginItemControllerTest {

    /**
     * 验证插件工具删除按稳定顺序锁定资源行。
     */
    @Test
    public void removeCheckShouldLockPluginItemsInStableOrder() {
        PluginItemService pluginItemService = mock(PluginItemService.class);
        AgentResourceReferenceService referenceService = mock(AgentResourceReferenceService.class);
        PluginService pluginService = mock(PluginService.class);
        PluginVisibilityService visibilityService = mock(PluginVisibilityService.class);
        PluginItem first = pluginItem(BigInteger.ONE, BigInteger.TEN);
        PluginItem second = pluginItem(BigInteger.TWO, BigInteger.TEN);
        Plugin plugin = new Plugin();
        plugin.setId(BigInteger.TEN);
        plugin.setTenantId(1L);
        plugin.setCreatedBy(1L);
        when(pluginItemService.list(any(QueryWrapper.class))).thenReturn(List.of(first, second));
        when(pluginService.getById(BigInteger.TEN)).thenReturn(plugin);
        PluginItemController controller = new PluginItemController(pluginItemService);
        setField(controller, "pluginItemService", pluginItemService);
        setField(controller, "agentResourceReferenceService", referenceService);
        setField(controller, "pluginService", pluginService);
        setField(controller, "pluginVisibilityService", visibilityService);
        LoginAccount loginAccount = new LoginAccount();
        loginAccount.setTenantId(BigInteger.ONE);

        try (MockedStatic<SaTokenUtil> login = mockStatic(SaTokenUtil.class)) {
            login.when(SaTokenUtil::getLoginAccount).thenReturn(loginAccount);
            controller.onRemoveBefore(List.of(BigInteger.TWO, BigInteger.ONE));
        }

        ArgumentCaptor<QueryWrapper> queryCaptor = ArgumentCaptor.forClass(QueryWrapper.class);
        verify(pluginItemService).list(queryCaptor.capture());
        String sql = queryCaptor.getValue().toSQL().toUpperCase(Locale.ROOT);
        Assert.assertTrue(sql.contains("ORDER BY"));
        Assert.assertTrue(sql.contains("FOR UPDATE"));
        verify(referenceService).assertPluginItemsUnused(List.of(BigInteger.TWO, BigInteger.ONE));
        verify(visibilityService).assertPluginVisible(1L, BigInteger.TEN, "无权限删除该插件工具");
    }

    /**
     * 创建插件工具。
     *
     * @param id 工具 ID
     * @param pluginId 插件 ID
     * @return 插件工具
     */
    private static PluginItem pluginItem(BigInteger id, BigInteger pluginId) {
        PluginItem pluginItem = new PluginItem();
        pluginItem.setId(id);
        pluginItem.setPluginId(pluginId);
        return pluginItem;
    }

    /**
     * 通过反射设置字段值。
     *
     * @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);
        }
    }
}
