import {
  getArchestraToolFullName,
  TOOL_GET_AGENT_SHORT_NAME,
  TOOL_WHOAMI_SHORT_NAME,
} from "@archestra/shared";
import { describe, expect, test } from "@/test";
import type { PolicyEvaluationContext } from "./tool-invocation-policy";
import ToolInvocationPolicyModel from "./tool-invocation-policy";

const mockContext: PolicyEvaluationContext = {
  teamIds: [],
};

describe("ToolInvocationPolicyModel", () => {
  describe("evaluateBatch", () => {
    test("returns success when all tools are allowed", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
    }) => {
      const agent = await makeAgent();
      const tool1 = await makeTool({ agentId: agent.id, name: "tool-1" });
      const tool2 = await makeTool({ agentId: agent.id, name: "tool-2" });
      await makeAgentTool(agent.id, tool1.id);
      await makeAgentTool(agent.id, tool2.id);

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          { toolCallName: "tool-1", toolInput: { arg: "value1" } },
          { toolCallName: "tool-2", toolInput: { arg: "value2" } },
        ],
        mockContext,
        true,
      );

      expect(result.isAllowed).toBe(true);
      expect(result.reason).toBe("");
      expect(result.toolCallName).toBeUndefined();
    });

    test("returns first blocked tool when multiple tools are blocked", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool1 = await makeTool({ agentId: agent.id, name: "tool-1" });
      const tool2 = await makeTool({ agentId: agent.id, name: "tool-2" });
      await makeAgentTool(agent.id, tool1.id);
      await makeAgentTool(agent.id, tool2.id);

      // Block both tools with specific conditions
      await makeToolPolicy(tool1.id, {
        conditions: [
          { key: "email", operator: "endsWith", value: "@evil.com" },
        ],
        action: "block_always",
        reason: "Tool 1 blocked",
      });
      await makeToolPolicy(tool2.id, {
        conditions: [
          { key: "email", operator: "endsWith", value: "@evil.com" },
        ],
        action: "block_always",
        reason: "Tool 2 blocked",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          { toolCallName: "tool-1", toolInput: { email: "bad@evil.com" } },
          { toolCallName: "tool-2", toolInput: { email: "bad@evil.com" } },
        ],
        mockContext,
        true,
      );

      expect(result.isAllowed).toBe(false);
      expect(result.toolCallName).toBe("tool-1"); // First blocked
      expect(result.reason).toContain("Tool 1 blocked");
    });

    test("prefers the agent's assigned row when a duplicate name exists", async ({
      makeAgent,
      makeAgentTool,
      makeInternalMcpCatalog,
      makeMcpServer,
      makeOrganization,
      makeTool,
      makeToolPolicy,
    }) => {
      const org = await makeOrganization();
      const agent = await makeAgent({ organizationId: org.id });
      const catalog = await makeInternalMcpCatalog({ organizationId: org.id });
      await makeMcpServer({ catalogId: catalog.id, scope: "org" });

      const assigned = await makeTool({
        catalogId: catalog.id,
        name: "dup-tool",
      });
      await makeAgentTool(agent.id, assigned.id);
      await makeToolPolicy(assigned.id, {
        action: "block_always",
        reason: "assigned dup blocked",
        conditions: [],
      });

      // An unassigned same-name row in another catalog with no policy. A global
      // name lookup could resolve this row and wrongly allow the call; the
      // assigned row must win.
      const otherCatalog = await makeInternalMcpCatalog({
        organizationId: org.id,
      });
      await makeTool({ catalogId: otherCatalog.id, name: "dup-tool" });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [{ toolCallName: "dup-tool", toolInput: {} }],
        mockContext,
        true,
      );

      expect(result.isAllowed).toBe(false);
      expect(result.reason).toContain("assigned dup blocked");
      expect(result.toolId).toBe(assigned.id);
    });

    test("returns success when only white-labeled built-in tools are in the batch", async ({
      makeAgent,
      seedAndAssignArchestraTools,
    }) => {
      const agent = await makeAgent();
      await seedAndAssignArchestraTools(agent.id);
      const brandedWhoami = getArchestraToolFullName(TOOL_WHOAMI_SHORT_NAME, {
        appName: "Acme Copilot",
        fullWhiteLabeling: true,
      });
      const brandedGetAgent = getArchestraToolFullName(
        TOOL_GET_AGENT_SHORT_NAME,
        {
          appName: "Acme Copilot",
          fullWhiteLabeling: true,
        },
      );

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          { toolCallName: brandedWhoami, toolInput: {} },
          { toolCallName: brandedGetAgent, toolInput: { id: "123" } },
        ],
        mockContext,
        false, // untrusted context
      );

      expect(result.isAllowed).toBe(true);
      expect(result.reason).toBe("");
    });

    test("evaluates policies for query_knowledge_sources unlike other Archestra tools", async ({
      makeAgent,
      makeToolPolicy,
      seedAndAssignArchestraTools,
    }) => {
      const agent = await makeAgent();
      await seedAndAssignArchestraTools(agent.id);

      // By default, seedAndAssignArchestraTools uses archestra__ prefix
      const kbToolName = "archestra__query_knowledge_sources";

      // Find the tool to apply policy to
      const { ToolModel } = await import("@/models");
      const tool = await ToolModel.findByName(kbToolName);
      if (!tool) throw new Error(`Tool ${kbToolName} not found`);

      // Apply a block_always policy to the KB tool
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "block_always",
        reason: "KB access forbidden",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [{ toolCallName: kbToolName, toolInput: { query: "test" } }],
        mockContext,
        true,
      );

      // It should be blocked, unlike whoami or other built-ins
      expect(result.isAllowed).toBe(false);
      expect(result.reason).toContain("KB access forbidden");
    });

    test("query_knowledge_sources can require approval", async ({
      makeAgent,
      makeToolPolicy,
      seedAndAssignArchestraTools,
    }) => {
      const agent = await makeAgent();
      await seedAndAssignArchestraTools(agent.id);
      const kbToolName = "archestra__query_knowledge_sources";

      const { ToolModel } = await import("@/models");
      const tool = await ToolModel.findByName(kbToolName);
      if (!tool) throw new Error(`Tool ${kbToolName} not found`);

      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "require_approval",
        reason: "Approve this search",
      });

      const needsApproval =
        await ToolInvocationPolicyModel.checkApprovalRequired(
          kbToolName,
          { query: "confidential" },
          mockContext,
        );

      expect(needsApproval).toBe(true);
    });

    test("other Archestra tools still bypass policies even when KB tool is restricted", async ({
      makeAgent,
      makeToolPolicy,
      seedAndAssignArchestraTools,
    }) => {
      const agent = await makeAgent();
      await seedAndAssignArchestraTools(agent.id);
      const kbToolName = "archestra__query_knowledge_sources";
      const whoamiToolName = "archestra__whoami";

      const { ToolModel } = await import("@/models");
      const kbTool = await ToolModel.findByName(kbToolName);
      const whoamiTool = await ToolModel.findByName(whoamiToolName);
      if (!kbTool) throw new Error(`Tool ${kbToolName} not found`);
      if (!whoamiTool) throw new Error(`Tool ${whoamiToolName} not found`);

      // Block BOTH tools via policies
      await makeToolPolicy(kbTool.id, {
        conditions: [],
        action: "block_always",
        reason: "KB blocked",
      });
      await makeToolPolicy(whoamiTool.id, {
        conditions: [],
        action: "block_always",
        reason: "Whoami blocked",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          { toolCallName: whoamiToolName, toolInput: {} },
          { toolCallName: kbToolName, toolInput: { query: "test" } },
        ],
        mockContext,
        true,
      );

      // whoami should bypass (it's first in the batch), but KB should be checked
      // Actually evaluateBatch filters out bypassable tools BEFORE evaluation.
      // So whoami is ignored, and only KB is evaluated.
      expect(result.isAllowed).toBe(false);
      expect(result.toolCallName).toBe(kbToolName);
      expect(result.reason).toContain("KB blocked");
    });

    test("skips Archestra tools and evaluates non-Archestra tools", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
      seedAndAssignArchestraTools,
    }) => {
      const agent = await makeAgent();
      await seedAndAssignArchestraTools(agent.id);

      const tool = await makeTool({ agentId: agent.id, name: "regular-tool" });
      await makeAgentTool(agent.id, tool.id);

      await makeToolPolicy(tool.id, {
        conditions: [{ key: "action", operator: "equal", value: "delete" }],
        action: "block_always",
        reason: "Delete blocked",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          { toolCallName: "archestra__whoami", toolInput: {} },
          { toolCallName: "regular-tool", toolInput: { action: "delete" } },
        ],
        mockContext,
        true,
      );

      expect(result.isAllowed).toBe(false);
      expect(result.toolCallName).toBe("regular-tool");
      expect(result.reason).toContain("Delete blocked");
    });

    test("returns success for empty tool calls array", async ({
      makeAgent,
    }) => {
      const agent = await makeAgent();

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [],
        mockContext,
        false,
      );

      expect(result.isAllowed).toBe(true);
      expect(result.reason).toBe("");
    });

    test("allows tool with allow_when_context_is_untrusted default policy", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();

      const tool = await makeTool({
        agentId: agent.id,
        name: "permissive-tool",
      });
      await makeAgentTool(agent.id, tool.id);
      // Delete auto-created default policies to set up our own
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      // Create default policy (empty conditions) that allows untrusted context
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "allow_when_context_is_untrusted",
        reason: "Tool allows untrusted data",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [{ toolCallName: "permissive-tool", toolInput: { arg: "value" } }],
        mockContext,
        false, // untrusted context
      );

      expect(result.isAllowed).toBe(true);
      expect(result.reason).toBe("");
    });

    test("blocks tool when no policies exist", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({ agentId: agent.id, name: "strict-tool" });
      await makeAgentTool(agent.id, tool.id);
      // Delete auto-created default policies to test the default block fallback
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [{ toolCallName: "strict-tool", toolInput: { arg: "value" } }],
        mockContext,
        false, // untrusted context
      );

      expect(result.isAllowed).toBe(false);
      expect(result.reason).toContain(
        "Blocked by default in sensitive context",
      );
    });

    test("allows tool when explicit allow rule matches in untrusted context", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({ agentId: agent.id, name: "guarded-tool" });
      await makeAgentTool(agent.id, tool.id);

      // Specific policy that allows certain paths in untrusted context
      await makeToolPolicy(tool.id, {
        conditions: [{ key: "path", operator: "startsWith", value: "/safe/" }],
        action: "allow_when_context_is_untrusted",
        reason: "Safe path allowed",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          {
            toolCallName: "guarded-tool",
            toolInput: { path: "/safe/file.txt" },
          },
        ],
        mockContext,
        false,
      );

      expect(result.isAllowed).toBe(true);
      expect(result.reason).toBe("");
    });

    test("block_always takes precedence in policy evaluation", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({ agentId: agent.id, name: "email-tool" });
      await makeAgentTool(agent.id, tool.id);

      // Default allow policy
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "allow_when_context_is_untrusted",
        reason: "Default allow",
      });

      // Specific block policy
      await makeToolPolicy(tool.id, {
        conditions: [{ key: "body", operator: "contains", value: "malicious" }],
        action: "block_always",
        reason: "Malicious content blocked",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          {
            toolCallName: "email-tool",
            toolInput: { body: "malicious content" },
          },
        ],
        mockContext,
        false,
      );

      expect(result.isAllowed).toBe(false);
      expect(result.toolCallName).toBe("email-tool");
      expect(result.reason).toContain("Malicious content blocked");
    });

    test("evaluates multiple tools with mixed results correctly", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();

      // Tool 1: allowed with default policy
      const tool1 = await makeTool({ agentId: agent.id, name: "allowed-tool" });
      await makeAgentTool(agent.id, tool1.id);
      await makeToolPolicy(tool1.id, {
        conditions: [],
        action: "allow_when_context_is_untrusted",
        reason: "Default allow",
      });

      // Tool 2: will be blocked by specific policy
      const tool2 = await makeTool({ agentId: agent.id, name: "blocked-tool" });
      await makeAgentTool(agent.id, tool2.id);
      await makeToolPolicy(tool2.id, {
        conditions: [],
        action: "allow_when_context_is_untrusted",
        reason: "Default allow",
      });
      await makeToolPolicy(tool2.id, {
        conditions: [{ key: "dangerous", operator: "equal", value: "true" }],
        action: "block_always",
        reason: "Dangerous operation blocked",
      });

      // Tool 3: would also be blocked, but tool 2 should be returned first
      const tool3 = await makeTool({
        agentId: agent.id,
        name: "another-blocked",
      });
      await makeAgentTool(agent.id, tool3.id);
      await makeToolPolicy(tool3.id, {
        conditions: [{ key: "bad", operator: "equal", value: "yes" }],
        action: "block_always",
        reason: "Bad operation",
      });

      const result = await ToolInvocationPolicyModel.evaluateBatch(
        agent.id,
        [
          { toolCallName: "allowed-tool", toolInput: { safe: "value" } },
          { toolCallName: "blocked-tool", toolInput: { dangerous: "true" } },
          { toolCallName: "another-blocked", toolInput: { bad: "yes" } },
        ],
        mockContext,
        true,
      );

      expect(result.isAllowed).toBe(false);
      expect(result.toolCallName).toBe("blocked-tool"); // First blocked in order
      expect(result.reason).toContain("Dangerous operation blocked");
    });

    describe("operator evaluation", () => {
      test("equal operator works correctly", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [{ key: "status", operator: "equal", value: "active" }],
          action: "block_always",
          reason: "Active status blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { status: "active" } }],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { status: "inactive" } }],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("notEqual operator works correctly", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "env", operator: "notEqual", value: "production" },
          ],
          action: "block_always",
          reason: "Non-production blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { env: "development" } }],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { env: "production" } }],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("contains operator works correctly", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "message", operator: "contains", value: "secret" },
          ],
          action: "block_always",
          reason: "Secret content blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { message: "This contains a secret value" },
            },
          ],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { message: "This is safe content" },
            },
          ],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("notContains operator works correctly", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "message", operator: "notContains", value: "approved" },
          ],
          action: "block_always",
          reason: "Unapproved content blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { message: "This is not yet ready" },
            },
          ],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { message: "This is approved content" },
            },
          ],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("startsWith operator works correctly", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [{ key: "path", operator: "startsWith", value: "/tmp/" }],
          action: "block_always",
          reason: "Temp paths blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { path: "/tmp/file.txt" } }],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { path: "/home/file.txt" },
            },
          ],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("endsWith operator works correctly", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [{ key: "file", operator: "endsWith", value: ".exe" }],
          action: "block_always",
          reason: "Executable files blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { file: "malware.exe" } }],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { file: "document.pdf" } }],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("regex operator works correctly", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            {
              key: "email",
              operator: "regex",
              value: "^[a-zA-Z0-9._%+-]+@example\\.com$",
            },
          ],
          action: "block_always",
          reason: "Example.com emails blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { email: "user@example.com" },
            },
          ],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { email: "user@other.com" },
            },
          ],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });
    });

    describe("nested argument paths", () => {
      test("evaluates nested paths using lodash get", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "user.email", operator: "endsWith", value: "@blocked.com" },
          ],
          action: "block_always",
          reason: "Blocked domain",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: {
                user: { email: "hacker@blocked.com", name: "Hacker" },
              },
            },
          ],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { user: { email: "user@allowed.com", name: "User" } },
            },
          ],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });
    });

    describe("missing arguments", () => {
      test("condition does not match when argument is missing", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);
        // Delete auto-created default policies to test the default block fallback
        await ToolInvocationPolicyModel.deleteByToolId(tool.id);

        // A specific policy that requires an argument
        await makeToolPolicy(tool.id, {
          conditions: [{ key: "required", operator: "equal", value: "yes" }],
          action: "allow_when_context_is_untrusted",
          reason: "Required argument",
        });

        // Since the condition doesn't match (missing argument), the specific policy doesn't apply
        // No default policy exists, so the engine blocks it by default in a sensitive context
        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { other: "value" } }],
          mockContext,
          false, // context is untrusted
        );

        expect(result.isAllowed).toBe(false);
        expect(result.reason).toContain(
          "Blocked by default in sensitive context",
        );
      });

      test("block policy does not apply when argument is missing", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [{ key: "optional", operator: "equal", value: "bad" }],
          action: "block_always",
          reason: "Bad value",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { other: "value" } }],
          mockContext,
          true, // context is trusted
        );

        expect(result.isAllowed).toBe(true);
        expect(result.reason).toBe("");
      });
    });

    describe("specific vs default policy precedence", () => {
      test("specific policy takes precedence over default policy", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        // Default policy: block in untrusted context
        await makeToolPolicy(tool.id, {
          conditions: [],
          action: "block_always",
          reason: "Default block",
        });

        // Specific policy: allow safe paths
        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "path", operator: "startsWith", value: "/safe/" },
          ],
          action: "allow_when_context_is_untrusted",
          reason: "Safe path allowed",
        });

        // Specific policy matches - should be allowed even though default blocks
        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { path: "/safe/file.txt" },
            },
          ],
          mockContext,
          false, // untrusted context
        );

        expect(result.isAllowed).toBe(true);
      });

      test("falls back to default policy when specific policy does not match", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);
        // Delete auto-created default policies to set up our own
        await ToolInvocationPolicyModel.deleteByToolId(tool.id);

        // Default policy: allow in untrusted context
        await makeToolPolicy(tool.id, {
          conditions: [],
          action: "allow_when_context_is_untrusted",
          reason: "Default allow",
        });

        // Specific policy: block dangerous paths
        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "path", operator: "startsWith", value: "/danger/" },
          ],
          action: "block_always",
          reason: "Dangerous path blocked",
        });

        // Specific policy doesn't match, fall back to default allow
        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { path: "/normal/file.txt" },
            },
          ],
          mockContext,
          false, // untrusted context
        );

        expect(result.isAllowed).toBe(true);
      });
    });

    describe("multiple conditions (AND logic)", () => {
      test("applies when all input conditions match", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "action", operator: "equal", value: "delete" },
            { key: "target", operator: "equal", value: "production" },
          ],
          action: "block_always",
          reason: "Cannot delete in production",
        });

        // Both conditions match - should be blocked
        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { action: "delete", target: "production" },
            },
          ],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);
        expect(blockedResult.reason).toContain("Cannot delete in production");
      });

      test("does not apply when only some input conditions match", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "action", operator: "equal", value: "delete" },
            { key: "target", operator: "equal", value: "production" },
          ],
          action: "block_always",
          reason: "Cannot delete in production",
        });

        // Only first condition matches - should be allowed
        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "test-tool",
              toolInput: { action: "delete", target: "staging" },
            },
          ],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("handles mixed context and input conditions", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "mixed-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            {
              key: "context.externalAgentId",
              operator: "equal",
              value: "restricted-agent",
            },
            { key: "action", operator: "equal", value: "delete" },
          ],
          action: "block_always",
          reason: "Restricted agent cannot delete",
        });

        // Both conditions match - should be blocked
        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "mixed-tool", toolInput: { action: "delete" } }],
          { teamIds: [], externalAgentId: "restricted-agent" },
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);
        expect(blockedResult.reason).toContain(
          "Restricted agent cannot delete",
        );

        // Only context condition matches - should be allowed
        const allowedResult1 = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "mixed-tool", toolInput: { action: "read" } }],
          { teamIds: [], externalAgentId: "restricted-agent" },
          true,
        );
        expect(allowedResult1.isAllowed).toBe(true);

        // Only data condition matches - should be allowed
        const allowedResult2 = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "mixed-tool", toolInput: { action: "delete" } }],
          { teamIds: [], externalAgentId: "other-agent" },
          true,
        );
        expect(allowedResult2.isAllowed).toBe(true);
      });
    });

    describe("context-based conditions", () => {
      test("blocks when context.externalAgentId matches with equal operator", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            {
              key: "context.externalAgentId",
              operator: "equal",
              value: "blocked-external-agent",
            },
          ],
          action: "block_always",
          reason: "External agent blocked",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { arg: "value" } }],
          {
            teamIds: [],
            externalAgentId: "blocked-external-agent",
          },
          true,
        );

        expect(result.isAllowed).toBe(false);
        expect(result.reason).toContain("External agent blocked");
      });

      test("allows when context.externalAgentId does not match with equal operator", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            {
              key: "context.externalAgentId",
              operator: "equal",
              value: "blocked-external-agent",
            },
          ],
          action: "block_always",
          reason: "External agent blocked",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { arg: "value" } }],
          {
            teamIds: [],
            externalAgentId: "allowed-external-agent",
          },
          true,
        );

        expect(result.isAllowed).toBe(true);
      });

      test("blocks when context.externalAgentId matches with notEqual operator", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            {
              key: "context.externalAgentId",
              operator: "notEqual",
              value: "trusted-agent",
            },
          ],
          action: "block_always",
          reason: "Only trusted agent allowed",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { arg: "value" } }],
          {
            teamIds: [],
            externalAgentId: "untrusted-agent",
          },
          true,
        );

        expect(result.isAllowed).toBe(false);
        expect(result.reason).toContain("Only trusted agent allowed");
      });

      test("blocks when context.teamIds matches with contains operator", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            {
              key: "context.teamIds",
              operator: "contains",
              value: "restricted-team-id",
            },
          ],
          action: "block_always",
          reason: "Team restricted",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { arg: "value" } }],
          {
            teamIds: ["other-team", "restricted-team-id"],
          },
          true,
        );

        expect(result.isAllowed).toBe(false);
        expect(result.reason).toContain("Team restricted");
      });

      test("allows when context.teamIds does not match with equal operator", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({ agentId: agent.id, name: "test-tool" });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            {
              key: "context.teamIds",
              operator: "equal",
              value: "restricted-team-id",
            },
          ],
          action: "block_always",
          reason: "Team restricted",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "test-tool", toolInput: { arg: "value" } }],
          {
            teamIds: ["allowed-team-1", "allowed-team-2"],
          },
          true,
        );

        expect(result.isAllowed).toBe(true);
      });
    });

    describe("tools with __ in server name", () => {
      test("evaluates policies for tools whose server name contains __", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        // Tool name like upstash__context7__resolve-library-id (server name contains __)
        const tool = await makeTool({
          agentId: agent.id,
          name: "upstash__context7__resolve-library-id",
        });
        await makeAgentTool(agent.id, tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "libraryId", operator: "equal", value: "blocked-lib" },
          ],
          action: "block_always",
          reason: "Library is blocked",
        });

        const blockedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "upstash__context7__resolve-library-id",
              toolInput: { libraryId: "blocked-lib" },
            },
          ],
          mockContext,
          true,
        );
        expect(blockedResult.isAllowed).toBe(false);
        expect(blockedResult.reason).toContain("Library is blocked");

        const allowedResult = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "upstash__context7__resolve-library-id",
              toolInput: { libraryId: "safe-lib" },
            },
          ],
          mockContext,
          true,
        );
        expect(allowedResult.isAllowed).toBe(true);
      });

      test("blocks tool with __ in server name when context is untrusted and default policy applies", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({
          agentId: agent.id,
          name: "huggingface__remote-mcp__generate_text",
        });
        await makeAgentTool(agent.id, tool.id);
        // Delete auto-created default policies to test the default block fallback
        await ToolInvocationPolicyModel.deleteByToolId(tool.id);

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "huggingface__remote-mcp__generate_text",
              toolInput: { prompt: "test" },
            },
          ],
          mockContext,
          false, // untrusted context
        );

        expect(result.isAllowed).toBe(false);
        expect(result.reason).toContain(
          "Blocked by default in sensitive context",
        );
      });

      test("allows tool with __ in server name when context is untrusted and explicit allow policy exists", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({
          agentId: agent.id,
          name: "upstash__context7__query-docs",
        });
        await makeAgentTool(agent.id, tool.id);
        // Delete auto-created default policies to set up our own
        await ToolInvocationPolicyModel.deleteByToolId(tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [],
          action: "allow_when_context_is_untrusted",
          reason: "Read-only tool allowed in untrusted context",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "upstash__context7__query-docs",
              toolInput: { query: "test" },
            },
          ],
          mockContext,
          false, // untrusted context
        );

        expect(result.isAllowed).toBe(true);
      });

      test("evaluates batch with mix of standard and __ server name tools", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();

        // Standard tool (no __ in server name)
        const standardTool = await makeTool({
          agentId: agent.id,
          name: "github__create-pull-request",
        });
        await makeAgentTool(agent.id, standardTool.id);

        // Tool with __ in server name
        const doubleUnderscoreTool = await makeTool({
          agentId: agent.id,
          name: "upstash__context7__resolve-library-id",
        });
        await makeAgentTool(agent.id, doubleUnderscoreTool.id);

        // Block the double-underscore tool
        await makeToolPolicy(doubleUnderscoreTool.id, {
          conditions: [
            { key: "libraryId", operator: "equal", value: "dangerous" },
          ],
          action: "block_always",
          reason: "Dangerous library blocked",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "github__create-pull-request",
              toolInput: { title: "test PR" },
            },
            {
              toolCallName: "upstash__context7__resolve-library-id",
              toolInput: { libraryId: "dangerous" },
            },
          ],
          mockContext,
          true,
        );

        expect(result.isAllowed).toBe(false);
        expect(result.toolCallName).toBe(
          "upstash__context7__resolve-library-id",
        );
        expect(result.reason).toContain("Dangerous library blocked");
      });
    });

    describe("require_approval action in evaluateBatch", () => {
      test("treats require_approval like allow_when_context_is_untrusted in proxy context", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({
          agentId: agent.id,
          name: "approval-tool",
        });
        await makeAgentTool(agent.id, tool.id);
        await ToolInvocationPolicyModel.deleteByToolId(tool.id);

        // Default policy: require_approval (should be treated as allow in proxy)
        await makeToolPolicy(tool.id, {
          conditions: [],
          action: "require_approval",
          reason: "Requires chat approval",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [{ toolCallName: "approval-tool", toolInput: { arg: "value" } }],
          mockContext,
          false, // untrusted context
        );

        // require_approval should NOT block in proxy (evaluateBatch)
        expect(result.isAllowed).toBe(true);
        expect(result.reason).toBe("");
      });

      test("treats specific require_approval policy like allow in proxy context", async ({
        makeAgent,
        makeTool,
        makeAgentTool,
        makeToolPolicy,
      }) => {
        const agent = await makeAgent();
        const tool = await makeTool({
          agentId: agent.id,
          name: "specific-approval-tool",
        });
        await makeAgentTool(agent.id, tool.id);
        await ToolInvocationPolicyModel.deleteByToolId(tool.id);

        await makeToolPolicy(tool.id, {
          conditions: [
            { key: "action", operator: "equal", value: "dangerous" },
          ],
          action: "require_approval",
          reason: "Requires approval for dangerous actions",
        });

        const result = await ToolInvocationPolicyModel.evaluateBatch(
          agent.id,
          [
            {
              toolCallName: "specific-approval-tool",
              toolInput: { action: "dangerous" },
            },
          ],
          mockContext,
          false,
        );

        expect(result.isAllowed).toBe(true);
        expect(result.reason).toBe("");
      });
    });
  });

  describe("checkApprovalRequired", () => {
    test("returns true when default policy has require_approval action", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({
        agentId: agent.id,
        name: "chat-approval-tool",
      });
      await makeAgentTool(agent.id, tool.id);
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "require_approval",
        reason: "Chat approval required",
      });

      const result = await ToolInvocationPolicyModel.checkApprovalRequired(
        "chat-approval-tool",
        { arg: "value" },
        mockContext,
      );

      expect(result).toBe(true);
    });

    test("returns false when default policy is allow_when_context_is_untrusted", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({
        agentId: agent.id,
        name: "allowed-chat-tool",
      });
      await makeAgentTool(agent.id, tool.id);
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "allow_when_context_is_untrusted",
        reason: "Allowed always",
      });

      const result = await ToolInvocationPolicyModel.checkApprovalRequired(
        "allowed-chat-tool",
        { arg: "value" },
        mockContext,
      );

      expect(result).toBe(false);
    });

    test("returns false when tool has no policies", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({
        agentId: agent.id,
        name: "no-policy-tool",
      });
      await makeAgentTool(agent.id, tool.id);
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      const result = await ToolInvocationPolicyModel.checkApprovalRequired(
        "no-policy-tool",
        {},
        mockContext,
      );

      expect(result).toBe(false);
    });

    test("returns false for archestra tools regardless of policies", async () => {
      const result = await ToolInvocationPolicyModel.checkApprovalRequired(
        "archestra__todo_write",
        { todos: [] },
        mockContext,
      );

      expect(result).toBe(false);
    });

    test("returns false when tool does not exist", async () => {
      const result = await ToolInvocationPolicyModel.checkApprovalRequired(
        "nonexistent-tool",
        {},
        mockContext,
      );

      expect(result).toBe(false);
    });

    test("returns true when specific policy matches with require_approval", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({
        agentId: agent.id,
        name: "conditional-approval-tool",
      });
      await makeAgentTool(agent.id, tool.id);
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      await makeToolPolicy(tool.id, {
        conditions: [{ key: "action", operator: "equal", value: "dangerous" }],
        action: "require_approval",
        reason: "Dangerous actions need approval",
      });

      // Matching input - should require approval
      const result = await ToolInvocationPolicyModel.checkApprovalRequired(
        "conditional-approval-tool",
        { action: "dangerous" },
        mockContext,
      );
      expect(result).toBe(true);

      // Non-matching input - should not require approval
      const safeResult = await ToolInvocationPolicyModel.checkApprovalRequired(
        "conditional-approval-tool",
        { action: "safe" },
        mockContext,
      );
      expect(safeResult).toBe(false);
    });

    test("specific non-approval policy takes precedence over default approval policy", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({
        agentId: agent.id,
        name: "precedence-tool",
      });
      await makeAgentTool(agent.id, tool.id);
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      // Default: require approval
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "require_approval",
        reason: "Default approval",
      });

      // Specific: allow safe paths without approval
      await makeToolPolicy(tool.id, {
        conditions: [{ key: "path", operator: "startsWith", value: "/safe/" }],
        action: "allow_when_context_is_untrusted",
        reason: "Safe paths allowed",
      });

      // Safe path matches specific policy - should NOT require approval
      const safeResult = await ToolInvocationPolicyModel.checkApprovalRequired(
        "precedence-tool",
        { path: "/safe/file.txt" },
        mockContext,
      );
      expect(safeResult).toBe(false);

      // Non-matching path falls through to default - should require approval
      const otherResult = await ToolInvocationPolicyModel.checkApprovalRequired(
        "precedence-tool",
        { path: "/other/file.txt" },
        mockContext,
      );
      expect(otherResult).toBe(true);
    });

    test("evaluates policies normally", async ({
      makeAgent,
      makeTool,
      makeAgentTool,
      makeToolPolicy,
    }) => {
      const agent = await makeAgent();
      const tool = await makeTool({
        agentId: agent.id,
        name: "restrictive-test-tool",
      });
      await makeAgentTool(agent.id, tool.id);
      await ToolInvocationPolicyModel.deleteByToolId(tool.id);

      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "require_approval",
        reason: "Should be enforced in restrictive mode",
      });

      const result = await ToolInvocationPolicyModel.checkApprovalRequired(
        "restrictive-test-tool",
        { arg: "value" },
        mockContext,
      );

      expect(result).toBe(true);
    });
  });

  describe("hasBlockingPolicy", () => {
    test("returns false for tool with allow_when_context_is_untrusted policy (trusted)", async ({
      makeTool,
      makeToolPolicy,
    }) => {
      const tool = await makeTool({ name: "always-allowed-tool" });
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "allow_when_context_is_untrusted",
      });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "always-allowed-tool",
        true,
      );
      expect(result).toBe(false);
    });

    test("returns false for tool with allow_when_context_is_untrusted policy (untrusted)", async ({
      makeTool,
      makeToolPolicy,
    }) => {
      const tool = await makeTool({ name: "always-allowed-untrusted" });
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "allow_when_context_is_untrusted",
      });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "always-allowed-untrusted",
        false,
      );
      expect(result).toBe(false);
    });

    test("returns true for tool with block_always policy", async ({
      makeTool,
      makeToolPolicy,
    }) => {
      const tool = await makeTool({ name: "blocked-tool" });
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "block_always",
      });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "blocked-tool",
        true,
      );
      expect(result).toBe(true);
    });

    test("returns true for tool with require_approval policy", async ({
      makeTool,
      makeToolPolicy,
    }) => {
      const tool = await makeTool({ name: "approval-tool" });
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "require_approval",
      });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "approval-tool",
        true,
      );
      expect(result).toBe(true);
    });

    test("returns true for tool with block_when_context_is_untrusted when untrusted", async ({
      makeTool,
      makeToolPolicy,
    }) => {
      const tool = await makeTool({ name: "untrusted-block-tool" });
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "block_when_context_is_untrusted",
      });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "untrusted-block-tool",
        false,
      );
      expect(result).toBe(true);
    });

    test("returns false for tool with block_when_context_is_untrusted when trusted", async ({
      makeTool,
      makeToolPolicy,
    }) => {
      const tool = await makeTool({ name: "trusted-context-tool" });
      await makeToolPolicy(tool.id, {
        conditions: [],
        action: "block_when_context_is_untrusted",
      });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "trusted-context-tool",
        true,
      );
      expect(result).toBe(false);
    });

    test("returns true for tool with custom conditions (any action)", async ({
      makeTool,
      makeToolPolicy,
    }) => {
      const tool = await makeTool({ name: "conditional-tool" });
      await makeToolPolicy(tool.id, {
        conditions: [{ key: "path", operator: "startsWith", value: "/etc/" }],
        action: "allow_when_context_is_untrusted",
      });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "conditional-tool",
        true,
      );
      expect(result).toBe(true);
    });

    test("returns false for tool with no policies", async ({ makeTool }) => {
      await makeTool({ name: "no-policy-tool" });

      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "no-policy-tool",
        true,
      );
      expect(result).toBe(false);
    });

    test("returns false for non-existent tool", async () => {
      const result = await ToolInvocationPolicyModel.hasBlockingPolicy(
        "non-existent-tool",
        true,
      );
      expect(result).toBe(false);
    });
  });
});
