// @vitest-environment jsdom
import { render, fireEvent } from "@testing-library/react";
import { ErrorBoundary } from "./ErrorBoundary.js";

// Suppress React error boundary console.error noise in test output
const originalConsoleError = console.error;
beforeAll(() => {
  console.error = vi.fn();
});
afterAll(() => {
  console.error = originalConsoleError;
});

function ThrowingChild({ shouldThrow }: { shouldThrow: boolean }) {
  if (shouldThrow) throw new Error("boom");
  return <span>ok</span>;
}

describe("ErrorBoundary", () => {
  it("renders children when no error", () => {
    const { getByText } = render(
      <ErrorBoundary>
        <span>hello</span>
      </ErrorBoundary>,
    );
    expect(getByText("hello")).toBeDefined();
  });

  it("shows default fallback with error message on throw", () => {
    const { getByRole, getByText } = render(
      <ErrorBoundary>
        <ThrowingChild shouldThrow />
      </ErrorBoundary>,
    );
    expect(getByRole("alert")).toBeDefined();
    expect(getByText("boom")).toBeDefined();
    expect(getByText("Retry")).toBeDefined();
  });

  it("shows custom fallback when provided", () => {
    const { getByText } = render(
      <ErrorBoundary fallback={<div>custom error</div>}>
        <ThrowingChild shouldThrow />
      </ErrorBoundary>,
    );
    expect(getByText("custom error")).toBeDefined();
  });

  it("resets when Retry is clicked", () => {
    // We need a component that can toggle throwing
    let shouldThrow = true;
    function Toggler() {
      if (shouldThrow) throw new Error("fail");
      return <span>recovered</span>;
    }

    const { getByText } = render(
      <ErrorBoundary>
        <Toggler />
      </ErrorBoundary>,
    );

    expect(getByText("fail")).toBeDefined();

    // Stop throwing before retry
    shouldThrow = false;
    fireEvent.click(getByText("Retry"));

    expect(getByText("recovered")).toBeDefined();
  });
});
