import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import type { RegexExecutionResult } from "../regex/model/match";
import type { RegexSyntaxResult } from "../regex/model/syntax";
import { CapabilityPanel } from "./CapabilityPanel";

const syntax: RegexSyntaxResult = {
  accepted: true,
  root: {
    id: "root",
    kind: "pattern",
    range: { startUtf16: 0, endUtf16: 1 },
    raw: "a",
    explanation: "Pattern",
    children: [],
    properties: {
      zeroWidth: false,
      nullable: false,
      minimumLength: 1,
      maximumLength: 1,
      consumesInput: true,
    },
    support: { flavour: "ecmascript", status: "supported", notes: [] },
    provenance: {
      provider: "fixture",
      providerVersion: "9",
      source: "parsed",
    },
  },
  tokens: [],
  captures: [],
  diagnostics: [],
  provider: { id: "fixture-provider", version: "9" },
  coverage: {
    status: "partial",
    summary: "Fixture coverage summary",
    unsupportedConstructs: ["fixture"],
  },
};

const execution: RegexExecutionResult = {
  accepted: true,
  engine: {
    flavour: "ecmascript",
    adapterVersion: "1",
    engineName: "Fixture engine",
    engineVersion: "123",
    offsetUnit: "utf8-byte",
    capabilities: {
      compilation: true,
      matching: true,
      replacement: false,
      namedCaptures: false,
      captureHistory: false,
      actualTrace: false,
      benchmark: false,
    },
  },
  flags: {
    userFlags: "",
    effectiveFlags: "d",
    internallyAddedIndicesFlag: true,
    internallyAddedGlobalFlag: false,
  },
  matches: [],
  diagnostics: [],
  elapsedMs: 1,
  truncated: false,
};

describe("CapabilityPanel", () => {
  it("renders the current provider and engine metadata without static drift", () => {
    render(<CapabilityPanel syntax={syntax} execution={execution} />);

    expect(screen.getByText("fixture-provider 9")).toBeInTheDocument();
    expect(
      screen.getByText("partial: Fixture coverage summary"),
    ).toBeInTheDocument();
    expect(screen.getByText("Fixture engine")).toBeInTheDocument();
    expect(screen.getByText("123")).toBeInTheDocument();
    expect(
      screen.getByText("Not separately reported by this adapter"),
    ).toBeInTheDocument();
    expect(screen.getByText("1", { selector: "dd" })).toBeInTheDocument();
    expect(screen.getByText("UTF-8 bytes")).toBeInTheDocument();
    expect(screen.getByText("fixture")).toBeInTheDocument();

    const replacement = screen.getByText("Replacement").closest("div");
    expect(replacement).toHaveTextContent("Unavailable");
    const compilation = screen.getByText("Compilation").closest("div");
    expect(compilation).toHaveTextContent("Available");
    const generatedCases = screen.getByText("Generated cases").closest("div");
    expect(generatedCases).toHaveTextContent(
      "deterministic AST candidates, retained only after actual-engine verification",
    );
    const formatting = screen.getByText("Pattern formatting").closest("div");
    expect(formatting).toHaveTextContent(
      "grammar-backed literal/control escaping with mandatory exact-snapshot validation",
    );
  });

  it("keeps PCRE2-only trace and code generation separate from ECMAScript-only tools", () => {
    render(
      <CapabilityPanel
        syntax={syntax}
        execution={{
          ...execution,
          engine: {
            ...execution.engine,
            flavour: "pcre2",
            engineName: "PCRE2",
            capabilities: {
              ...execution.engine.capabilities,
              actualTrace: true,
            },
          },
        }}
      />,
    );

    const trace = screen.getByText("Actual execution trace").closest("div");
    expect(trace).toHaveTextContent("Available");
    const generatedCases = screen.getByText("Generated cases").closest("div");
    expect(generatedCases).toHaveTextContent(
      "Unavailable — the ECMAScript case generator is not applied to PCRE2",
    );
    const formatting = screen.getByText("Pattern formatting").closest("div");
    expect(formatting).toHaveTextContent(
      "Unavailable — the ECMAScript formatter is not applied to PCRE2",
    );
    const codeGeneration = screen.getByText("Code generation").closest("div");
    expect(codeGeneration).toHaveTextContent(
      "Available — reviewed PCRE2 10.47 8-bit C17 target",
    );
  });

  it.each([
    ["python", "Python re"],
    ["java", "Java Pattern"],
    ["php", "PHP preg / PCRE2"],
    ["perl", "Perl (legacy WebPerl)"],
    ["ruby", "Ruby Regexp"],
    ["cpp", "C++ std::regex"],
    ["go", "Go regexp"],
    ["rust", "Rust regex"],
    ["dotnet", ".NET Regex"],
    ["scala", "Scala Regex / Java compatibility"],
  ] as const)(
    "does not borrow ECMAScript or PCRE2 feature semantics for %s",
    (flavour, label) => {
      render(
        <CapabilityPanel
          syntax={syntax}
          execution={{
            ...execution,
            engine: {
              ...execution.engine,
              flavour,
              engineName: `${label} fixture`,
            },
          }}
        />,
      );

      expect(
        screen.getByText("Actual execution trace").closest("div"),
      ).toHaveTextContent(
        "Unavailable — automatic-callout tracing is implemented only for PCRE2",
      );
      expect(
        screen.getByText("Static risk analysis").closest("div"),
      ).toHaveTextContent(
        `Unavailable — ECMAScript heuristics are not applied to ${label}`,
      );
      expect(
        screen.getByText("Generated cases").closest("div"),
      ).toHaveTextContent(
        `Unavailable — the ECMAScript case generator is not applied to ${label}`,
      );
      expect(
        screen.getByText("Pattern formatting").closest("div"),
      ).toHaveTextContent(
        `Unavailable — the ECMAScript formatter is not applied to ${label}`,
      );
      expect(
        screen.getByText("Code generation").closest("div"),
      ).toHaveTextContent(
        "Unavailable — C17 code generation is implemented only for PCRE2",
      );
    },
  );

  it("offers an accessible close control when used as a modal panel", async () => {
    const onClose = vi.fn();
    const user = userEvent.setup();
    render(
      <CapabilityPanel
        syntax={syntax}
        execution={execution}
        onClose={onClose}
      />,
    );

    await user.click(
      screen.getByRole("button", { name: "Close capabilities" }),
    );
    expect(onClose).toHaveBeenCalledOnce();
  });
});
