import { render, screen, fireEvent } from '@testing-library/react';
import { ThemeProvider } from '../../theme';
import ErrorBoundary from './ErrorBoundary';

function Bomb({ shouldThrow }: { shouldThrow: boolean }) {
  if (shouldThrow) throw new Error('boom');
  return <div>safe content</div>;
}

const COPY = { title: 'Something went wrong', body: 'Please try again.', retryLabel: 'Retry' };

describe('<ErrorBoundary/>', () => {
  const wrap = (ui: React.ReactNode) => render(<ThemeProvider>{ui}</ThemeProvider>);

  it('renders children when nothing throws', () => {
    wrap(
      <ErrorBoundary name="Test" {...COPY}>
        <Bomb shouldThrow={false} />
      </ErrorBoundary>,
    );
    expect(screen.getByText('safe content')).toBeInTheDocument();
  });

  it('renders the branded fallback with a retry affordance when a child throws', () => {
    const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
    wrap(
      <ErrorBoundary name="Test" {...COPY}>
        <Bomb shouldThrow={true} />
      </ErrorBoundary>,
    );
    expect(screen.getByText('Something went wrong')).toBeInTheDocument();
    expect(screen.getByRole('button', { name: 'Retry' })).toBeInTheDocument();
    errorSpy.mockRestore();
  });

  it('re-renders children after retry is clicked (state resets)', () => {
    const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
    const { rerender } = render(
      <ThemeProvider>
        <ErrorBoundary name="Test" {...COPY}>
          <Bomb shouldThrow={true} />
        </ErrorBoundary>
      </ThemeProvider>,
    );
    expect(screen.getByText('Something went wrong')).toBeInTheDocument();

    // Swap in a child that no longer throws BEFORE retrying — the boundary's `hasError` state
    // only clears on retry, and re-rendering while it's still true keeps showing the fallback
    // (it doesn't re-invoke the previously-thrown children). Retry re-renders `this.props.children`
    // with whatever was most recently passed down, so the non-throwing swap must land first.
    rerender(
      <ThemeProvider>
        <ErrorBoundary name="Test" {...COPY}>
          <Bomb shouldThrow={false} />
        </ErrorBoundary>
      </ThemeProvider>,
    );
    fireEvent.click(screen.getByRole('button', { name: 'Retry' }));
    expect(screen.getByText('safe content')).toBeInTheDocument();
    errorSpy.mockRestore();
  });
});
