package tech.easyflow.admin.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import org.testng.Assert;
import org.testng.annotations.Test;
import tech.easyflow.admin.controller.agent.AgentSessionController;
import tech.easyflow.admin.controller.ai.ChatHistoryController;
import tech.easyflow.admin.controller.ai.ModelController;
import tech.easyflow.admin.controller.ai.WorkFlowNodeController;
import tech.easyflow.admin.controller.ai.WorkflowController;
import tech.easyflow.admin.controller.dashboard.DashboardController;
import tech.easyflow.admin.controller.job.SysJobController;
import tech.easyflow.admin.controller.system.ApprovalFlowController;
import tech.easyflow.admin.controller.system.SysAccountController;
import tech.easyflow.admin.controller.system.SysRoleController;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 管理端页面能力接口权限归属契约测试。
 */
public class PermissionIsolationContractTest {

    /**
     * 验证工作流设计器依赖的选项接口只要求工作流查询权限。
     */
    @Test
    public void workflowDesignerOptionsBelongToWorkflowPermission() {
        assertMethodPermission(
                WorkflowController.class,
                "designerOptions",
                "/api/v1/workflow/query"
        );
        assertMethodPermission(
                WorkflowController.class,
                "designerChildWorkflow",
                "/api/v1/workflow/query"
        );
        assertMethodPermission(
                WorkFlowNodeController.class,
                "getChainParams",
                "/api/v1/workflow/query"
        );
    }

    /**
     * 验证各管理页面的辅助能力接口使用页面自身权限。
     */
    @Test
    public void pageOptionsBelongToOwningPagePermissions() {
        assertMethodPermission(ModelController.class, "gatewayConfig", "/api/v1/model/query");
        assertMethodPermission(DashboardController.class, "agentOptions", "/api/v1/dashboard/query");
        assertMethodPermission(SysJobController.class, "workflowOptions", "/api/v1/sysJob/save");
        assertMethodPermission(SysJobController.class, "getNextTimes", "/api/v1/sysJob/save");
        assertMethodPermission(ApprovalFlowController.class, "resourceScopeOptions", "/api/v1/approvalFlow/save");
        assertMethodPermission(SysRoleController.class, "formOptions", "/api/v1/sysRole/query");
        assertMethodPermission(SysAccountController.class, "formOptions", "/api/v1/sysAccount/save");
    }

    /**
     * 验证 Agent 会话和聊天历史接口分别使用各自页面权限。
     */
    @Test
    public void agentSessionAndHistoryUseIndependentPermissions() {
        assertClassPermission(AgentSessionController.class, "/api/v1/agent/session/query");
        assertClassPermission(ChatHistoryController.class, "/api/v1/chatHistory/query");
    }

    /**
     * 断言控制器方法只声明指定权限。
     *
     * @param controllerType 控制器类型
     * @param methodName 方法名
     * @param expectedPermission 期望权限
     */
    private void assertMethodPermission(
            Class<?> controllerType,
            String methodName,
            String expectedPermission) {
        Method method = Arrays.stream(controllerType.getDeclaredMethods())
                .filter(candidate -> methodName.equals(candidate.getName()))
                .findFirst()
                .orElseThrow(() -> new AssertionError("未找到控制器方法：" + methodName));
        SaCheckPermission permission = method.getAnnotation(SaCheckPermission.class);

        Assert.assertNotNull(permission, methodName + " 缺少权限注解");
        Assert.assertEquals(permission.value(), new String[]{expectedPermission});
    }

    /**
     * 断言控制器类只声明指定权限。
     *
     * @param controllerType 控制器类型
     * @param expectedPermission 期望权限
     */
    private void assertClassPermission(Class<?> controllerType, String expectedPermission) {
        SaCheckPermission permission = controllerType.getAnnotation(SaCheckPermission.class);

        Assert.assertNotNull(permission, controllerType.getSimpleName() + " 缺少权限注解");
        Assert.assertEquals(permission.value(), new String[]{expectedPermission});
    }
}
