import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it } from "vitest";
import type {
  RegexExecutionResult,
  RegexReplacementResult,
} from "../regex/model/match";
import { ReplacementPanel } from "./ReplacementPanel";

afterEach(cleanup);

const execution: RegexExecutionResult = {
  accepted: true,
  engine: {
    flavour: "ecmascript",
    adapterVersion: "test",
    engineName: "Test ECMAScript engine",
    engineVersion: "test",
    offsetUnit: "utf16",
    capabilities: {
      compilation: true,
      matching: true,
      replacement: true,
      namedCaptures: true,
      captureHistory: false,
      actualTrace: false,
      benchmark: false,
    },
  },
  flags: {
    userFlags: "g",
    effectiveFlags: "dg",
    internallyAddedIndicesFlag: true,
    internallyAddedGlobalFlag: false,
  },
  matches: [],
  diagnostics: [],
  elapsedMs: 1,
  truncated: false,
};

function renderResult(result: RegexReplacementResult) {
  return render(
    <ReplacementPanel
      replacement="x"
      onReplacementChange={() => undefined}
      result={result}
      onSelectToken={() => undefined}
      onSelectContribution={() => undefined}
    />,
  );
}

describe("ReplacementPanel completeness", () => {
  it.each([
    ["python", "Python re"],
    ["java", "Java Pattern"],
  ] as const)(
    "labels %s templates without relabelling them",
    (flavour, label) => {
      render(
        <ReplacementPanel
          flavour={flavour}
          replacement=""
          onReplacementChange={() => undefined}
          onSelectToken={() => undefined}
          onSelectContribution={() => undefined}
        />,
      );

      expect(screen.getByText(`${label} template syntax`)).toBeInTheDocument();
      expect(
        screen.getByText(`Native matches · bounded ${label} substitution`),
      ).toBeInTheDocument();
    },
  );

  it("labels a match-limited replacement as partial", () => {
    renderResult({
      execution: { ...execution, truncated: true },
      output: "xa",
      outputBytes: 2,
      outputTruncated: false,
      truncated: true,
    });

    expect(
      screen.getByRole("heading", { name: "Replacement output" }),
    ).toBeInTheDocument();
    expect(screen.queryByText("Complete output")).not.toBeInTheDocument();
    expect(
      screen.getByText(/partial · match\/capture limit reached/u),
    ).toBeInTheDocument();
    expect(screen.getByTestId("replacement-match-limit")).toHaveTextContent(
      "later subject text remains unchanged",
    );
  });

  it("distinguishes byte-truncated output from match incompleteness", () => {
    renderResult({
      execution,
      output: "prefix",
      outputBytes: 6,
      outputTruncated: true,
      truncated: true,
    });

    expect(screen.getByText(/output preview truncated/u)).toBeInTheDocument();
    expect(
      screen.queryByTestId("replacement-match-limit"),
    ).not.toBeInTheDocument();
  });
});
