import { render, screen } from '@testing-library/react';
import React from 'react';
import { LazyRouteErrorBoundary } from '../lazy-route-error-boundary';

class ChunkLoadError extends Error {
    constructor(message: string) {
        super(message);
        this.name = 'ChunkLoadError';
    }
}

const Thrower: React.FC<{ error: Error }> = ({ error }) => {
    throw error;
};

describe('<LazyRouteErrorBoundary>', () => {
    // React logs caught errors to console.error; silence for these tests.
    let consoleErrorSpy: jest.SpyInstance;
    beforeEach(() => {
        consoleErrorSpy = jest
            .spyOn(console, 'error')
            .mockImplementation(() => undefined);
    });
    afterEach(() => {
        consoleErrorSpy.mockRestore();
    });

    it('renders children when no error', () => {
        render(
            <LazyRouteErrorBoundary>
                <p>child content</p>
            </LazyRouteErrorBoundary>
        );
        expect(screen.getByText('child content')).toBeInTheDocument();
    });

    it('renders the refresh banner on ChunkLoadError with role="alert" for a11y', () => {
        const err = new ChunkLoadError('Loading chunk 42 failed');
        render(
            <LazyRouteErrorBoundary>
                <Thrower error={err} />
            </LazyRouteErrorBoundary>
        );
        // role="alert" wrapper is required because suite-components' <Alert>
        // does not set ARIA attributes on its own root (verified by reading
        // alert.tsx lines 167-183). Asserting on the role here means a
        // future PR removing the wrapper for "cleanliness" breaks the test.
        const alertRegion = screen.getByRole('alert');
        expect(alertRegion).toBeInTheDocument();
        expect(
            screen.getByText(/new version of abacus is available/i)
        ).toBeInTheDocument();
        expect(screen.getByText(/save any unsaved work/i)).toBeInTheDocument();
        expect(
            screen.getByRole('button', { name: /reload page/i })
        ).toBeInTheDocument();
    });

    it('re-throws non-chunk errors', () => {
        const err = new Error('totally unrelated error');
        // The boundary must NOT swallow this. Wrapping with try/catch in the
        // test framework — React 18+ rethrows from boundaries during render.
        expect(() =>
            render(
                <LazyRouteErrorBoundary>
                    <Thrower error={err} />
                </LazyRouteErrorBoundary>
            )
        ).toThrow('totally unrelated error');
    });
});
