import { describe, expect, it } from "vitest";
import { validateProviderDecision } from "./provider-decision-validator.js";
import type { RequiredToolConstraint } from "./tool-constraint-types.js";

const shellToolCall = { input: {}, toolName: "shell" };
const tools = [
  { description: "Read a file.", effect: "read" as const, name: "read-file" },
  { description: "Run a shell command.", effect: "execute" as const, name: "shell" },
];

function requiredToolConstraint(
  overrides: Partial<RequiredToolConstraint>,
): RequiredToolConstraint {
  return {
    forbiddenToolNames: [],
    reason: "explicit-required-tool",
    requiredReleasePolicy: "none",
    requiredToolNames: [],
    restrictionScope: "turn",
    ...overrides,
  };
}

describe("provider decision validator", () => {
  it("does not reject tool self-selection through action policy requirements", () => {
    const result = validateProviderDecision({
      actionPolicy: {
        allowedActions: ["tool"],
        directResponseAllowed: false,
        required: {
          kind: "tool",
          reason: "explicit-required-tool",
          requiredAnyToolNames: ["read-file"],
          toolNames: ["read-file"],
        },
      },
      availableTools: tools,
      decision: {
        kind: "tool",
        model: "test-model",
        provider: "openai",
        toolCalls: [shellToolCall],
      },
      knownToolNames: ["read-file", "shell"],
      profileAllowedToolNames: ["read-file", "shell"],
      profileName: "default",
      selectedToolCalls: [shellToolCall],
      threadMode: "default",
      visibleTools: tools,
    });

    expect(result).toEqual({ ok: true });
  });

  it("accepts non-forbidden required-tool wrong selections", () => {
    const result = validateProviderDecision({
      actionPolicy: {
        allowedActions: ["tool"],
        directResponseAllowed: false,
      },
      availableTools: tools,
      decision: {
        kind: "tool",
        model: "test-model",
        provider: "openai",
        toolCalls: [shellToolCall],
      },
      knownToolNames: ["read-file", "shell"],
      profileAllowedToolNames: ["read-file", "shell"],
      profileName: "default",
      requiredToolConstraint: requiredToolConstraint({
        requiredToolNames: ["read-file"],
        selectableToolNames: ["read-file"],
      }),
      selectedToolCalls: [shellToolCall],
      threadMode: "default",
      visibleTools: tools,
    });

    expect(result).toEqual({ ok: true });
  });

  it("keeps tool-not-allowed for forbidden required-tool selections", () => {
    const result = validateProviderDecision({
      actionPolicy: {
        allowedActions: ["tool"],
        directResponseAllowed: false,
      },
      availableTools: tools,
      decision: {
        kind: "tool",
        model: "test-model",
        provider: "openai",
        toolCalls: [shellToolCall],
      },
      knownToolNames: ["read-file", "shell"],
      profileAllowedToolNames: ["read-file", "shell"],
      profileName: "default",
      requiredToolConstraint: requiredToolConstraint({
        forbiddenToolNames: ["shell"],
        requiredToolNames: ["read-file"],
      }),
      selectedToolCalls: [shellToolCall],
      threadMode: "default",
      visibleTools: tools,
    });

    expect(result).toMatchObject({
      ok: false,
      reasonCode: "tool-not-allowed",
      source: "required-tool",
    });
  });
});
