import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import IdentityContext from 'src/context';
import queries from 'src/queries';
import { formatMessage } from 'src/utils';
import { TERM_ID, TERM_PLACEHOLDER, TERM_ERROR } from '../constants';
import WorkstationGlobalSearch from '../ws-global-search';

describe('<WorkstationGlobalSearch>', () => {
    const identity = { id: 1 } as any;
    const defaultProps = {
        idPrefix: 'test',
        idSequence: () => 0,
    };

    const unresolved: any = {
        then: () => unresolved,
        catch: () => unresolved,
    };

    const renderComponent = () =>
        render(
            <IdentityContext.Provider value={{ identity } as any}>
                <MemoryRouter>
                    <WorkstationGlobalSearch {...defaultProps} />
                </MemoryRouter>
            </IdentityContext.Provider>
        );

    beforeEach(() => {
        jest.spyOn(queries, 'createGlobalSearchQuery').mockReturnValue(
            () => unresolved
        );
    });

    test('renders the placeholder text', () => {
        const input = renderComponent().getByText(
            formatMessage(`${TERM_ID}.${TERM_PLACEHOLDER}`)
        );
        expect(input).toBeVisible();
    });

    describe('when searching', () => {
        test('renders loading indicator', async () => {
            const wrapper = renderComponent();
            const input = wrapper.getByRole('combobox');
            fireEvent.change(input, { target: { value: 'a' } });

            const indicatorNode = await wrapper.findByTestId(
                'gs-loading-indicator'
            );

            expect(indicatorNode).toBeVisible();
        });
    });

    describe('when failed searching', () => {
        beforeEach(() => {
            jest.spyOn(queries, 'createGlobalSearchQuery').mockReturnValue(
                async () => await Promise.reject(new Error('error'))
            );
        });

        test('renders error message', async () => {
            const wrapper = renderComponent();
            const input = wrapper.getByRole('combobox');
            fireEvent.change(input, { target: { value: 'naive' } });

            const errorNode = await wrapper.findByText(
                formatMessage(`${TERM_ID}.${TERM_ERROR}`)
            );

            expect(errorNode).toBeVisible();
        });
    });

    describe('when completed searching', () => {
        const term = 'I want an option';
        const optionTitle = 'Im an option!';
        const options = [
            { type: 'product', value: 1, title: optionTitle, count: 1 },
        ];
        const service = jest.fn().mockResolvedValue(options);

        beforeEach(() => {
            jest.spyOn(queries, 'createGlobalSearchQuery').mockReturnValue(
                service
            );
        });

        test('renders search results', async () => {
            const wrapper = renderComponent();
            const input = wrapper.getByRole('combobox');
            fireEvent.change(input, { target: { value: term } });

            const optionNode = await wrapper.findByText(optionTitle);

            expect(service).toHaveBeenCalledWith({ term, queryId: 0 });
            expect(optionNode).toBeVisible();
        });
    });
});
