import React from 'react';
import { render } from '@testing-library/react';
import { ErrorBoundary } from '@theorchard/suite-components';
import { formatMessage } from '@theorchard/suite-i18n';
import { MemoryRouter } from 'react-router-dom';
import { mockConsoleError } from '../../../../lib/test-utils/console';
import { MainNavSectionOptions } from '../../../types';
import * as routeUtils from '../../../utils/routing';
import { MainNavSection, MainNavSectionProps } from '../mainNavSection';

describe('<MainNavSection>', () => {
    const item1 = { path: '/path1', title: 'item 1' };
    const item2 = { path: '/path2', title: 'item 2' };
    const onError = vi.fn();

    const renderComponent = (props: MainNavSectionProps, pathname = '/') =>
        render(<MainNavSection {...props} />, {
            wrapper: ({ children }) => (
                <ErrorBoundary onError={onError}>
                    <MemoryRouter initialEntries={[{ pathname }]}>{children}</MemoryRouter>
                </ErrorBoundary>
            ),
        });

    beforeEach(() => {
        onError.mockClear();
    });

    test('renders title, id, type className and items', () => {
        const section = {
            id: '1',
            title: 'section title',
            type: 'primary',
            items: [item1, item2],
        } satisfies MainNavSectionOptions<unknown>;

        const { getByText, container } = renderComponent({ section });

        expect(container.firstChild).toHaveAttribute('id', 'NavSection-1');
        expect(container.firstChild).toHaveClass('NavSection-primary');

        const element = getByText(section.title);
        expect(element).toBeVisible();

        section.items.forEach((item) => expect(getByText(item.title)).toBeVisible());

        const header = container.querySelector('.NavSection-header');
        expect(header).toBeVisible();
    });

    test('does not render header if title is not defined', () => {
        const section = { id: '1', items: [item1, item2] };
        const { container } = renderComponent({ section });

        const element = container.querySelector('.NavSection-header');
        expect(element).toBeNull();
    });

    test('renders beta badge if beta flag is defined', () => {
        const section = {
            id: '1',
            title: 'test',
            beta: true,
            items: [item1, item2],
        };
        const { container } = renderComponent({ section });

        const element = container.querySelector('.BetaBadge');
        expect(element).toBeVisible();
    });

    test('renders translated term', () => {
        const section = {
            id: '1',
            title: 'not shown',
            term: 'navigation_account',
            items: [item1, item2],
        };
        const { getByText, queryByText } = renderComponent({ section });

        const element = getByText(formatMessage(section.term));
        expect(element).toBeVisible();

        const titleElement = queryByText(section.title);
        expect(titleElement).toBeNull();
    });

    test('throws if no item "path" or "routeId" is provided', () => {
        mockConsoleError(() => {
            const section = {
                id: '1',
                items: [item1, {}],
            };

            const { getByText } = renderComponent({ section });

            const element = getByText('Sorry, we hit a snag');
            expect(element).toBeVisible();
            expect(onError).toHaveBeenCalledTimes(1);
        });
    });

    test('does not throw if no "path", but "routeId" is provided', () => {
        const itemTitle = 'with route id';

        const route = {
            id: 'test-route',
            path: '/test-path',
            moduleName: 'test',
            page: () => <></>,
        };

        vi.spyOn(routeUtils, 'getRoute').mockImplementation((id) =>
            id === route.id ? route : undefined
        );

        mockConsoleError(() => {
            const section = {
                id: '1',
                items: [item1, { routeId: route.id, title: itemTitle }],
            };

            const { getByText } = renderComponent({ section });
            const element = getByText(itemTitle);

            expect(element).toBeInTheDocument();
            expect(onError).not.toHaveBeenCalled();
        });
    });

    describe('links with custom "Component"', () => {
        test('renders custom link component', () => {
            const text = 'custom text';
            const { getByText } = renderComponent({
                section: {
                    id: 'test',
                    items: [
                        {
                            path: '/test',
                            Component: () => <div>{text}</div>,
                        },
                    ],
                },
            });

            expect(getByText(text)).toBeVisible();
        });
    });

    test('each link is a NavLink', () => {
        const { getAllByTestId } = renderComponent({
            section: {
                id: 'test',
                items: [item1, item2],
            },
        });

        expect(getAllByTestId('NavLink')).toHaveLength(2);
    });
});
