package tech.easyflow.skill.service;

import com.mybatisflex.core.query.QueryWrapper;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.MockedStatic;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.mapper.PluginMapper;
import tech.easyflow.ai.permission.McpAccessPermissionChecker;
import tech.easyflow.ai.service.McpService;
import tech.easyflow.ai.service.PluginItemService;
import tech.easyflow.ai.service.PluginVisibilityService;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.skill.vo.SkillToolOptionPage;
import tech.easyflow.system.service.ResourceAccessService;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * Skill Tool 候选权限边界测试。
 */
public class SkillToolOptionQueryServiceTest {

    /**
     * 验证聚合查询在缺少 MCP 权限时仍返回其他已授权候选。
     */
    @Test
    public void allShouldOmitMcpWithoutBlockingOtherCandidates() {
        Dependencies dependencies = new Dependencies();
        LoginAccount account = account();
        Workflow workflow = new Workflow();
        workflow.setId(BigInteger.TEN);
        workflow.setTenantId(account.getTenantId());
        workflow.setTitle("合同审批");
        workflow.setDescription("审批合同");
        workflow.setPublishStatus(PublishStatus.PUBLISHED.getCode());
        // tb_workflow.status 是历史字段，线上可用性以发布状态为准。
        workflow.setStatus(0);
        when(dependencies.workflowService.list(any(QueryWrapper.class))).thenReturn(List.of(workflow));
        when(dependencies.resourceAccessService.canAccess(any(), any(), any())).thenReturn(true);
        when(dependencies.pluginMapper.selectListByQuery(any(QueryWrapper.class))).thenReturn(List.of());
        when(dependencies.mcpAccessPermissionChecker.canUseMcp()).thenReturn(false);

        try (MockedStatic<SaTokenUtil> login = mockStatic(SaTokenUtil.class)) {
            login.when(SaTokenUtil::getLoginAccount).thenReturn(account);

            SkillToolOptionPage result = dependencies.service().page(null, "ALL", 1, 20);

            Assert.assertEquals(1L, result.total());
            Assert.assertEquals("WORKFLOW", result.records().get(0).toolType());
            verify(dependencies.mcpService, never()).list(any(QueryWrapper.class));
        }
    }

    /**
     * 验证显式查询 MCP 时仍严格要求 MCP 权限。
     */
    @Test
    public void explicitMcpShouldRejectMissingPermission() {
        Dependencies dependencies = new Dependencies();
        doThrow(new BusinessException(403, 403, "无权限查询或使用 MCP"))
                .when(dependencies.mcpAccessPermissionChecker).assertCanUseMcp();

        try (MockedStatic<SaTokenUtil> login = mockStatic(SaTokenUtil.class)) {
            login.when(SaTokenUtil::getLoginAccount).thenReturn(account());
            try {
                dependencies.service().page(null, "MCP", 1, 20);
                Assert.fail("显式 MCP 查询必须校验权限");
            } catch (BusinessException exception) {
                Assert.assertEquals(403, exception.getHttpStatus());
            }
        }
    }

    private LoginAccount account() {
        LoginAccount account = new LoginAccount();
        account.setId(BigInteger.ONE);
        account.setTenantId(BigInteger.valueOf(42));
        return account;
    }

    /**
     * 查询服务依赖夹具。
     */
    private static final class Dependencies {

        private final WorkflowService workflowService = mock(WorkflowService.class);
        private final PluginItemService pluginItemService = mock(PluginItemService.class);
        private final PluginMapper pluginMapper = mock(PluginMapper.class);
        private final PluginVisibilityService pluginVisibilityService = mock(PluginVisibilityService.class);
        private final McpService mcpService = mock(McpService.class);
        private final McpAccessPermissionChecker mcpAccessPermissionChecker =
                mock(McpAccessPermissionChecker.class);
        private final SkillToolResourceService resourceService = mock(SkillToolResourceService.class);
        private final ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);

        /**
         * 创建待测服务。
         *
         * @return 待测服务
         */
        private SkillToolOptionQueryService service() {
            return new SkillToolOptionQueryService(
                    workflowService,
                    pluginItemService,
                    pluginMapper,
                    pluginVisibilityService,
                    mcpService,
                    mcpAccessPermissionChecker,
                    resourceService,
                    resourceAccessService
            );
        }
    }
}
