import { describe, it } from 'vitest';
import assert from "node:assert/strict";
import { z } from "zod";

import { validateToolArguments } from "../../pi-ai/src/utils/validation.ts";
import { registerWorkflowTools } from "./workflow-tools.ts";

type RegisteredTool = {
  name: string;
  description: string;
  params: Record<string, unknown>;
};

function makeMockServer() {
  const tools: RegisteredTool[] = [];
  return {
    tools,
    tool(
      name: string,
      description: string,
      params: Record<string, unknown>,
      _handler: (args: Record<string, unknown>) => Promise<unknown>,
    ) {
      tools.push({ name, description, params });
    },
  };
}

function workflowToolSchema(toolName: string): Record<string, unknown> {
  const server = makeMockServer();
  registerWorkflowTools(server as any);
  const tool = server.tools.find((candidate) => candidate.name === toolName);
  assert.ok(tool, `${toolName} should be registered`);

  const schema = z.toJSONSchema(z.object(tool.params as z.ZodRawShape)) as Record<string, unknown>;
  delete schema.$schema;
  return schema;
}

function makeToolCall(overrides: Record<string, unknown>) {
  return {
    type: "toolCall" as const,
    id: "call-1",
    name: "sf_complete_task",
    arguments: {
      projectDir: "/tmp/sf-project",
      taskId: "T01",
      sliceId: "S01",
      milestoneId: "M001",
      oneLiner: "Completed task",
      narrative: "Did the work.",
      verification: "npm test",
      ...overrides,
    },
  };
}

describe("string-array schema coercion", () => {
  const sfCompleteTaskTool = {
    name: "sf_complete_task",
    description: "Record a completed task to the SF database and render its SUMMARY.md.",
    parameters: workflowToolSchema("sf_complete_task") as any,
  };

  it("coerces a bare string keyDecisions value before validation", () => {
    const args = validateToolArguments(
      sfCompleteTaskTool,
      makeToolCall({ keyDecisions: "single string" }),
    );

    assert.deepEqual(args.keyDecisions, ["single string"]);
  });

  it("keeps an array keyDecisions value valid", () => {
    const args = validateToolArguments(
      sfCompleteTaskTool,
      makeToolCall({ keyDecisions: ["a", "b"] }),
    );

    assert.deepEqual(args.keyDecisions, ["a", "b"]);
  });

  it("rejects a non-string, non-array keyDecisions value", () => {
    assert.throws(
      () => validateToolArguments(sfCompleteTaskTool, makeToolCall({ keyDecisions: 42 })),
      /keyDecisions: must be array/,
    );
  });

  it("allows an undefined optional keyDecisions value", () => {
    const args = validateToolArguments(
      sfCompleteTaskTool,
      makeToolCall({ keyDecisions: undefined }),
    );

    assert.equal(args.keyDecisions, undefined);
  });
});
