import { describe, expect, it } from "vitest";

import { describeTraceLine } from "@/components/thread/activity/trace-activity-model";
import type { GenericToolStatus } from "@/components/thread/activity/generic-tool-model";

function describeTrace(line: string, status: GenericToolStatus = "done") {
  return describeTraceLine(line, status);
}

describe("trace activity semantics", () => {
  it("uses readable copy when a hosted search query is unavailable", () => {
    expect(describeTrace("web_search()").label).toBe("Searched the web");
  });

  it.each([
    ['web_search({"query":"nanobot latest release"})', "done", "Searched nanobot latest release", ""],
    ['web_fetch({"url":"https://example.com/docs?token=private"})', "done", "Read", "example.com/docs"],
    ['read_file({"path":"/Users/alice/project/README.md"})', "done", "Read", "~/project/README.md"],
    ['exec({"command":"date +%Y-%m-%d"})', "done", "Checked current time", ""],
    ['exec_command({"cmd":"API_KEY=secret npm test"})', "running", "Running command", "API_KEY=•••• npm test"],
    ['write_file({"path":"/home/alice/project/output.txt"})', "done", "Wrote file", "~/project/output.txt"],
    ['apply_patch({"file_path":"src/app.tsx","patch":"private"})', "error", "Could not edit file", "src/app.tsx"],
    ['third_party_sync({"token":"secret","payload":"private"})', "done", "Completed Third party sync", ""],
    ["Finished collecting results", "done", "Completed step", "Finished collecting results"],
  ] as const)("describes %s as one safe activity line", (line, status, label, detail) => {
    const result = describeTrace(line, status);
    expect(result).toMatchObject({ label, detail });
    expect(`${result.label} ${result.detail}`).not.toMatch(/[{}]|private|\/Users\/alice|\/home\/alice/);
  });

  it.each([
    ["running", "Searching status test"],
    ["done", "Searched status test"],
    ["error", "Could not search status test"],
  ] as const)("uses status-aware search copy for %s", (status, label) => {
    expect(describeTrace('web_search({"query":"status test"})', status).label).toBe(label);
  });

  it.each([
    ["running", "Searching X · status test"],
    ["done", "Searched X · status test"],
    ["error", "Could not search X · status test"],
  ] as const)("identifies hosted X search activity for %s", (status, label) => {
    expect(describeTrace('x_search({"query":"status test"})', status).label).toBe(label);
  });

  it("never exposes URL credentials, query secrets, or private-network links", () => {
    const publicResult = describeTrace(
      'web_fetch({"url":"https://user:password@example.com/docs?api_key=secret#section"})',
    );
    expect(publicResult).toMatchObject({ detail: "example.com/docs", host: "example.com" });
    expect(JSON.stringify(publicResult)).not.toMatch(/password|api_key|secret/);

    const privateResult = describeTrace('web_fetch({"url":"http://127.0.0.1:8765/private"})');
    expect(privateResult.url).toBeUndefined();
    expect(privateResult.detail).not.toContain("127.0.0.1");
  });

  it("summarizes multi-line commands without exposing every script line", () => {
    const result = describeTrace(
      'exec({"command":"npm test\\necho second-secret-line\\necho third-line"})',
    );
    expect(result).toMatchObject({
      label: "Ran command",
      detail: "npm test · script, 3 lines",
    });
    expect(result.detail).not.toContain("second-secret-line");
  });
});
