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

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

  it("should find all matches with global flag", async () => {
    const result = await runRegexTester(
      { text: "\\d+\nabc123def456ghi789" },
      { flags: "gi" },
      mockContext
    );
    expect(result.type).toBe("json");
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    const matches = value.matches as unknown[];
    expect(value.matchCount).toBe(3);
    expect(matches[0]).toEqual({ match: "123", index: 3, groups: null });
    expect(matches[1]).toEqual({ match: "456", index: 9, groups: null });
    expect(matches[2]).toEqual({ match: "789", index: 15, groups: null });
  });

  it("should find a single match without global flag", async () => {
    const result = await runRegexTester(
      { text: "hello\nsay hello world" },
      { flags: "i" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    const matches = value.matches as Array<Record<string, unknown>>;
    expect(value.matchCount).toBe(1);
    expect(matches[0].match).toBe("hello");
    expect(matches[0].index).toBe(4);
  });

  it("should return empty matches when test text is empty", async () => {
    const result = await runRegexTester(
      { text: "\\d+" },
      { flags: "gi" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.matchCount).toBe(0);
    expect(value.matches).toEqual([]);
  });

  it("should throw on invalid regex pattern", async () => {
    await expect(
      runRegexTester({ text: "[invalid" }, { flags: "gi" }, mockContext)
    ).rejects.toThrow("Invalid regex");
  });

  it("should throw when no pattern is provided", async () => {
    await expect(
      runRegexTester({ text: "" }, { flags: "gi" }, mockContext)
    ).rejects.toThrow("Enter a regex pattern");
  });

  it("should parse /pattern/flags syntax from input", async () => {
    const result = await runRegexTester(
      { text: "/hello/gi\nhello Hello HELLO" },
      { flags: "" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.matchCount).toBe(3);
  });

  it("should handle no matches gracefully", async () => {
    const result = await runRegexTester(
      { text: "xyz\nhello world" },
      { flags: "gi" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.matchCount).toBe(0);
    expect(value.matches).toEqual([]);
  });

  it("should find matches when using group input values", async () => {
    const result = await runRegexTester(
      {
        values: {
          pattern: { text: "\\d+" },
          text: { text: "abc123def456ghi789" },
        },
      },
      { flags: "gi" },
      mockContext
    );
    expect(result.type).toBe("json");
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    const matches = value.matches as unknown[];
    expect(value.matchCount).toBe(3);
    expect(matches[0]).toEqual({ match: "123", index: 3, groups: null });
  });
});
