import React from 'react';
import { render } from '@testing-library/react';
import { SuiteInitContext, SuitePlugin, SuiteErrorCategory } from '../../types';
import { ERROR_CODES } from '../../utils';
import { SuiteAppWrapper } from '../suiteAppWrapper';

describe('<SuiteAppWrapper>', () => {
    const plugin1Text = 'Plugin One';
    const plugin2Text = 'Plugin Two';
    const highPrioPluginText = 'First!';

    const plugin1: SuitePlugin = {
        Wrapper: ({ children }) => (
            <>
                <li>{plugin1Text}</li>
                {children}
            </>
        ),
    };
    const plugin2: SuitePlugin = {
        Wrapper: ({ children }) => (
            <>
                <li>{plugin2Text}</li>
                {children}
            </>
        ),
    };
    const highPrioPlugin: SuitePlugin = {
        priority: 'high',
        Wrapper: ({ children }) => (
            <ul>
                <li>{highPrioPluginText}</li>
                {children}
            </ul>
        ),
    };

    const plugins = [plugin1, {}, highPrioPlugin, plugin2];

    const context = {
        config: {
            appName: 'test',
            appTitle: 'test',
            brand: 'orchard',
            environment: 'prod',
        },
    } as SuiteInitContext;

    test('renders plugin wrappers in correct order', () => {
        const { container } = render(
            <SuiteAppWrapper loading={false} plugins={plugins} data={context} />
        );
        const [firstElement, secondElement, thirdElement] = Array.from(
            container.firstChild?.childNodes ?? []
        );

        expect(container).toMatchSnapshot();
        expect(firstElement).toHaveTextContent(highPrioPluginText);
        expect(secondElement).toHaveTextContent(plugin1Text);
        expect(thirdElement).toHaveTextContent(plugin2Text);
    });

    describe('is loading', () => {
        test('renders high prio wrappers then built-in loading wrapper', () => {
            const { container } = render(
                <SuiteAppWrapper loading plugins={plugins} data={context} />
            );
            const [firstElement, secondElement, thirdElement] = Array.from(
                container.firstChild?.childNodes ?? []
            );

            expect(container).toMatchSnapshot();
            expect(firstElement).toHaveTextContent(highPrioPluginText);
            expect(secondElement).toHaveTextContent('Please wait');
            expect(thirdElement).toBeUndefined();
        });
    });

    describe('has fatal error', () => {
        test('renders high prio wrappers then built-in error wrapper', () => {
            const { container } = render(
                <SuiteAppWrapper
                    error={{
                        name: 'fatal',
                        message: 'fatal',
                        category: SuiteErrorCategory.Fatal,
                        code: ERROR_CODES.FAILED_TO_START,
                    }}
                    loading={false}
                    plugins={plugins}
                    data={context}
                />
            );
            const [firstElement, secondElement, thirdElement] = Array.from(
                container.firstChild?.childNodes ?? []
            );

            expect(container).toMatchSnapshot();
            expect(firstElement).toHaveTextContent(highPrioPluginText);
            expect(secondElement).toHaveTextContent('Failed to start the application');
            expect(thirdElement).toBeUndefined();
        });
    });

    describe('has normal error', () => {
        test('renders all wrappers', () => {
            const { container } = render(
                <SuiteAppWrapper
                    error={{ name: 'normal', message: 'oops' }}
                    loading={false}
                    plugins={plugins}
                    data={context}
                />
            );
            const [firstElement, secondElement, thirdElement] = Array.from(
                container.firstChild?.childNodes ?? []
            );

            expect(container).toMatchSnapshot();
            expect(firstElement).toHaveTextContent(highPrioPluginText);
            expect(secondElement).toHaveTextContent(plugin1Text);
            expect(thirdElement).toHaveTextContent(plugin2Text);
        });
    });
});
