import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { REFERENCE_BY_FLAVOUR } from "../regex/reference/token-reference";
import { QuickReference } from "./QuickReference";

describe("QuickReference", () => {
  it("shows flavour, flags, example and authoritative source before insertion", async () => {
    const onUsePattern = vi.fn();
    const user = userEvent.setup();
    render(<QuickReference onUsePattern={onUsePattern} />);

    await user.type(
      screen.getByLabelText("Filter constructs"),
      "Any character",
    );
    expect(screen.getByText("ecmascript")).toBeInTheDocument();
    expect(screen.getByText("s", { selector: "dd" })).toBeInTheDocument();
    expect(screen.getByText("a.b")).toBeInTheDocument();
    expect(
      screen.getByRole("link", { name: "ECMAScript Atom grammar" }),
    ).toHaveAttribute("href", expect.stringContaining("tc39.es"));

    await user.click(
      screen.getByRole("button", { name: "Use example as pattern" }),
    );
    expect(onUsePattern).toHaveBeenCalledWith("a.b");
  });

  it("shows an explicit empty state for a filter without matches", async () => {
    const user = userEvent.setup();
    render(<QuickReference onUsePattern={vi.fn()} />);

    await user.type(
      screen.getByLabelText("Filter constructs"),
      "no such construct",
    );

    expect(screen.getByRole("status")).toHaveTextContent(
      "No reference constructs match",
    );
    expect(screen.getByText("0 of 12 constructs")).toBeInTheDocument();
  });

  it("switches to the authoritative PCRE2 construct set", async () => {
    const user = userEvent.setup();
    render(<QuickReference flavour="pcre2" onUsePattern={vi.fn()} />);

    expect(screen.getByText("Original PCRE2 reference")).toBeInTheDocument();
    expect(screen.getByText("8 of 8 constructs")).toBeInTheDocument();
    await user.type(screen.getByLabelText("Filter constructs"), "branch reset");
    expect(screen.getByText("Branch-reset group")).toBeInTheDocument();
    expect(
      screen.getByRole("link", { name: "PCRE2 pattern documentation" }),
    ).toHaveAttribute("href", expect.stringContaining("pcre.org"));
  });

  it("shows an original Python 3.14 re reference without borrowing ECMAScript syntax", async () => {
    const user = userEvent.setup();
    render(<QuickReference flavour="python" onUsePattern={vi.fn()} />);

    expect(
      screen.getByText("Original Python 3.14 re reference"),
    ).toBeInTheDocument();
    expect(screen.getByText("8 of 8 constructs")).toBeInTheDocument();

    await user.type(screen.getByLabelText("Filter constructs"), "absolute end");

    expect(screen.getByText("Absolute end anchor")).toBeInTheDocument();
    expect(screen.getByText("\\z")).toBeInTheDocument();
    expect(screen.getByText("python")).toBeInTheDocument();
    expect(
      screen.getByRole("link", { name: "Python 3.14 re documentation" }),
    ).toHaveAttribute("href", "https://docs.python.org/3.14/library/re.html");
  });

  it("shows an original Java Pattern reference from the official Java API", async () => {
    const user = userEvent.setup();
    render(<QuickReference flavour="java" onUsePattern={vi.fn()} />);

    expect(
      screen.getByText("Original Java Pattern reference"),
    ).toBeInTheDocument();
    expect(screen.getByText("9 of 9 constructs")).toBeInTheDocument();
    expect(
      screen.getByText(
        /bundled TeaVM 0\.15\.0 adapter is a tested compatibility subset/u,
      ),
    ).toBeInTheDocument();

    await user.type(screen.getByLabelText("Filter constructs"), "intersection");

    expect(
      screen.getByText("Character-class intersection"),
    ).toBeInTheDocument();
    expect(screen.getByText("[class&&class]")).toBeInTheDocument();
    expect(screen.getByText("java")).toBeInTheDocument();
    expect(
      screen.getByRole("link", {
        name: "Java SE 25 Pattern documentation",
      }),
    ).toHaveAttribute(
      "href",
      "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/regex/Pattern.html",
    );
  });

  it("shows a Go-owned partial reference without relabelling it as ECMAScript", () => {
    render(<QuickReference flavour="go" onUsePattern={vi.fn()} />);

    expect(
      screen.getByText("Original Go 1.26 regexp reference"),
    ).toBeInTheDocument();
    expect(screen.getByText("3 of 3 constructs")).toBeInTheDocument();
    expect(screen.getByText("Linear-time syntax boundary")).toBeInTheDocument();
    expect(
      screen.getAllByRole("link", {
        name: "Go regexp/syntax documentation",
      })[0],
    ).toHaveAttribute("href", "https://pkg.go.dev/regexp/syntax");
    expect(screen.queryByText("Any character")).not.toBeInTheDocument();
  });

  it("provides non-empty flavour-owned references for every new profile", () => {
    for (const flavour of [
      "php",
      "perl",
      "ruby",
      "cpp",
      "go",
      "rust",
      "dotnet",
      "scala",
    ] as const) {
      const reference = REFERENCE_BY_FLAVOUR[flavour];
      expect(reference.entries.length, flavour).toBeGreaterThan(0);
      expect(
        reference.entries.every(
          (entry) =>
            entry.flavours.length === 1 && entry.flavours[0] === flavour,
        ),
        flavour,
      ).toBe(true);
    }
  });
});
