import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { flatMap, range } from 'lodash';
import SearchResultOption, { CLASSNAME } from '../../search-result-option';
import SearchResults from '../search-results';

describe('<SearchResults>', () => {
    const defaultProps = {
        footerType: 'link',
        optionRenderer: ({ title }: { title?: string }) => title,
        optionComponent: SearchResultOption,
        valueKey: 'value',
    };

    const renderComponent = (props = {}) =>
        render(<SearchResults {...defaultProps} {...props} />);

    const term = 'some text';
    const types = ['group1', 'group2'];
    const count = 2;
    const options = flatMap(types, type =>
        range(0, 2).map(value => ({
            type,
            value,
            title: `option${value}`,
            count,
            term,
        }))
    );

    test('renders one header per type', () => {
        const formatMessage = jest.fn(msg => msg);
        const { getAllByText } = renderComponent({ options, formatMessage });

        types.forEach(type => {
            expect(formatMessage).toHaveBeenCalledWith(`${type}Plural`);
            expect(getAllByText(`${type}Plural`)).toHaveLength(1);
        });
    });

    test('renders one footer per type', () => {
        const formatMessage = jest.fn(msg => msg);
        const { container } = renderComponent({ options, formatMessage });

        // Each type renders a footer div with class GlobalSearchResults-footer
        const footers = container.querySelectorAll(
            '.GlobalSearchResults-footer'
        );
        expect(footers.length).toEqual(types.length);
    });

    test('renders options', () => {
        const { container } = renderComponent({ options });
        const optionEls = container.querySelectorAll(`.${CLASSNAME}`);
        expect(optionEls.length).toEqual(types.length * 2);
    });

    test('assigns "is-focused" class to focusedOption', () => {
        const focusedOption = {
            type: 'group1',
            value: 99,
            title: 'focused option',
            count,
            term,
        };
        const { getByText } = renderComponent({
            options: [...options, focusedOption],
            focusedOption,
        });
        expect(
            getByText(focusedOption.title).closest(
                `[data-testid="${CLASSNAME}"]`
            )
        ).toHaveClass('is-focused');
    });

    test('assigns "is-selected" class to selected options', () => {
        const selectedOption = {
            type: 'group1',
            value: 99,
            title: 'selected option',
            count,
            term,
        };
        const { getByText } = renderComponent({
            options: [...options, selectedOption],
            valueArray: [selectedOption],
        });
        expect(
            getByText(selectedOption.title).closest(
                `[data-testid="${CLASSNAME}"]`
            )
        ).toHaveClass('is-selected');
    });

    test('assigns "is-disabled" class to disabled options', () => {
        const disabled = [
            {
                type: 'product',
                value: 11,
                title: 'disabledOption1',
                disabled: true,
            },
            {
                type: 'project',
                value: 22,
                title: 'disabledOption2',
                disabled: true,
            },
        ];
        const { getAllByTestId } = renderComponent({
            options: [...options, ...disabled],
        });
        const disabledEls = getAllByTestId(CLASSNAME).filter(el =>
            el.classList.contains('is-disabled')
        );
        expect(disabledEls).toHaveLength(disabled.length);
    });

    test('onFooterClick is called when footer clicked', () => {
        const onFooterClick = jest.fn();
        const formatMessage = jest.fn(msg => msg);
        const { container } = renderComponent({
            options,
            onFooterClick,
            formatMessage,
        });

        // Click the first footer
        const footers = container.querySelectorAll(
            '.GlobalSearchResults-footer'
        );
        fireEvent.click(footers[0]);

        const [type] = types;
        expect(onFooterClick).toHaveBeenCalledWith({ type, term });
    });

    test('onSelect is called when option clicked', () => {
        const onSelect = jest.fn();
        const { container } = renderComponent({ options, onSelect });

        // Click the first option
        const optionEls = container.querySelectorAll(`.${CLASSNAME}`);
        fireEvent.click(optionEls[0]);

        const [option] = options;
        expect(onSelect).toHaveBeenCalledWith(option);
    });
});
