import { describe, expect, it } from "vitest";
import { createRandomId } from "@best-agent/foundation";
import type { Item, ThreadId, TurnId } from "@best-agent/protocol";
import { ToolRegistry, createDefaultToolRegistry, type ToolDefinition } from "../tool/registry.js";
import { buildMicrocompressedToolLedgerConversation } from "./tool-ledger.js";

function createLedgerItemBase(threadId: ThreadId, turnId: TurnId) {
  return {
    createdAt: new Date().toISOString(),
    id: createRandomId<"ItemId">("item"),
    threadId,
    turnId,
  };
}

describe("tool ledger", () => {
  it("keeps recent results when their calls are just outside the recent window", () => {
    const registry = new ToolRegistry([
      {
        capabilities() {
          return [];
        },
        description: "ledger test tool",
        execute() {
          return "";
        },
        executionClass: "read-only",
        idempotent: true,
        inputSchema: { type: "string" },
        name: "ledger-tool",
        source: "built-in",
        summarize(input, output) {
          return `ledger-tool ${input} -> ${output}`;
        },
      } satisfies ToolDefinition<string>,
    ]);
    const threadId = "thread-ledger" as ThreadId;
    const turnId = "turn-ledger" as TurnId;
    const callA = createRandomId<"ItemId">("item");
    const callB = createRandomId<"ItemId">("item");
    const callC = createRandomId<"ItemId">("item");

    const items: Item[] = [
      {
        ...createLedgerItemBase(threadId, turnId),
        callId: callA,
        input: "alpha",
        kind: "tool-call",
        historyInput: "alpha",
        toolName: "ledger-tool",
      },
      {
        ...createLedgerItemBase(threadId, turnId),
        callId: callB,
        input: "beta",
        kind: "tool-call",
        historyInput: "beta",
        toolName: "ledger-tool",
      },
      {
        ...createLedgerItemBase(threadId, turnId),
        callId: callC,
        input: "gamma",
        kind: "tool-call",
        historyInput: "gamma",
        toolName: "ledger-tool",
      },
      {
        ...createLedgerItemBase(threadId, turnId),
        callId: callA,
        kind: "tool-result",
        outcome: "success",
        output: "alpha output",
        toolName: "ledger-tool",
      },
      {
        ...createLedgerItemBase(threadId, turnId),
        callId: callB,
        kind: "tool-result",
        outcome: "success",
        output: "beta output",
        toolName: "ledger-tool",
      },
      {
        ...createLedgerItemBase(threadId, turnId),
        callId: callC,
        kind: "tool-result",
        outcome: "success",
        output: "gamma output",
        toolName: "ledger-tool",
      },
    ];

    const ledger = buildMicrocompressedToolLedgerConversation(items, 4, registry)[0]?.content;

    expect(ledger).toContain("ledger-tool alpha -> alpha output");
    expect(ledger).toContain("ledger-tool beta -> beta output");
    expect(ledger).toContain("ledger-tool gamma -> gamma output");
  });

  it("does not summarize display-only object tool inputs as undefined", () => {
    const registry = createDefaultToolRegistry();
    const threadId = "thread-ledger" as ThreadId;
    const turnId = "turn-ledger" as TurnId;
    const callId = createRandomId<"ItemId">("item");
    const items: Item[] = [
      {
        ...createLedgerItemBase(threadId, turnId),
        callId,
        input: "targetSymbol",
        kind: "tool-call",
        toolName: "content-search",
      },
      {
        ...createLedgerItemBase(threadId, turnId),
        callId,
        kind: "tool-result",
        outcome: "success",
        output: "MATCH package.json:1 targetSymbol",
        toolName: "content-search",
      },
    ];

    const ledger = buildMicrocompressedToolLedgerConversation(items, 4, registry)[0]?.content;

    expect(ledger).not.toContain("undefined");
    expect(ledger).toContain("targetSymbol");
  });
});
