import { describe, it, expect, vi } from "vitest";
import { runTextDiff } from "./run";
import type { ToolContext } from "../../core/plugins/plugin-types";

describe("Text Diff", () => {
  const mockContext: ToolContext = {
    signal: new AbortController().signal,
    reportProgress: vi.fn(),
    logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
  };

  it("should detect added lines", async () => {
    const result = await runTextDiff(
      { values: { original: { text: "line 1" }, modified: { text: "line 1\nline 2" } } },
      { ignoreWhitespace: false },
      mockContext
    );
    expect(result.type).toBe("text");
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("+ line 2");
    expect(value).toContain("  line 1");
  });

  it("should detect removed lines", async () => {
    const result = await runTextDiff(
      { values: { original: { text: "line 1\nline 2" }, modified: { text: "line 1" } } },
      { ignoreWhitespace: false },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("- line 2");
    expect(value).toContain("  line 1");
  });

  it("should detect identical texts", async () => {
    const result = await runTextDiff(
      { values: { original: { text: "same text" }, modified: { text: "same text" } } },
      { ignoreWhitespace: false },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("  same text");
    expect(value).toContain("0 added, 0 removed");
  });

  it("should show summary with counts", async () => {
    const result = await runTextDiff(
      { values: { original: { text: "a\nb\nc" }, modified: { text: "a\nx\nc\nd" } } },
      { ignoreWhitespace: false },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("Summary:");
    expect(value).toContain("added");
    expect(value).toContain("removed");
    expect(value).toContain("unchanged");
  });

  it("should ignore whitespace when option is set", async () => {
    const result = await runTextDiff(
      { values: { original: { text: "hello   world" }, modified: { text: "hello world" } } },
      { ignoreWhitespace: true },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("0 added, 0 removed");
  });

  it("should throw when one side is missing", async () => {
    await expect(
      runTextDiff(
        { values: { original: { text: "just one text" } } },
        { ignoreWhitespace: false },
        mockContext
      )
    ).rejects.toThrow("Both original and modified text are required");
  });

  it("should throw on empty input", async () => {
    await expect(
      runTextDiff({ values: {} }, { ignoreWhitespace: false }, mockContext)
    ).rejects.toThrow("No text provided");
  });

  it("should handle completely different texts", async () => {
    const result = await runTextDiff(
      { values: { original: { text: "aaa\nbbb" }, modified: { text: "xxx\nyyy" } } },
      { ignoreWhitespace: false },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("- aaa");
    expect(value).toContain("- bbb");
    expect(value).toContain("+ xxx");
    expect(value).toContain("+ yyy");
  });

  it("should still support legacy separator-based input", async () => {
    const result = await runTextDiff(
      { text: "line 1\n---\nline 1\nline 2" },
      { ignoreWhitespace: false },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("+ line 2");
  });
});
