import React from 'react';
import { fireEvent, render as renderDom } from '@testing-library/react';
import { testComponent } from 'lib/test-utils/common';
import { SearchDropdownCTA } from '../searchDropdownCTA';
import { SearchDropdownCTAProps } from '../types';

describe('<SearchDropdownCTA>', () => {
    const name = 'country';
    const option1 = { label: 'Option1', value: '1', data: { id: 1 } };
    const option2 = { label: 'Option2', value: '2', data: { id: 2 } };
    const options = [option1, option2];
    const content = 'Click me';
    const placeholder = 'Type to search';

    const render = (props?: Partial<SearchDropdownCTAProps>) =>
        renderDom(
            <SearchDropdownCTA
                name={name}
                onLoadOptions={async () => await Promise.resolve(options)}
                placeholder={placeholder}
                {...props}
            >
                <>{content}</>
            </SearchDropdownCTA>
        );

    testComponent(SearchDropdownCTA);

    test('renders children', () => {
        const { getByText } = render();

        const element = getByText(content);

        expect(element).toBeInTheDocument();
    });

    test('renders dropdown when clicking on children', async () => {
        const { getByText, findByText } = render();

        const element = getByText(content);

        fireEvent.click(element);

        const placeholderElement = await findByText(placeholder);

        expect(placeholderElement).toBeInTheDocument();
    });

    test('does not close dropdown when clicking on an option', async () => {
        const { container, getByText, findByText } = render({
            closeMenuOnSelect: false,
        });

        const element = getByText(content);
        const dropdownElement = container.querySelector('.dropdown');

        expect(dropdownElement).not.toHaveClass('show');

        fireEvent.click(element);

        expect(dropdownElement).toHaveClass('show');

        await findByText(placeholder);

        const input = container.querySelector('.Select__input');

        fireEvent.change(input!, { target: { value: 'abc' } });

        const optionElement1 = await findByText(option1.label);

        fireEvent.click(optionElement1);

        expect(dropdownElement).toHaveClass('show');
    });

    describe('with "closeOnMenuSelect" enabled', () => {
        test('closes dropdown when clicking on an option', async () => {
            const { container, getByText, findByText } = render({
                closeMenuOnSelect: true,
            });

            const element = getByText(content);
            const dropdownElement = container.querySelector('.dropdown');

            expect(dropdownElement).not.toHaveClass('show');

            fireEvent.click(element);

            expect(dropdownElement).toHaveClass('show');

            await findByText(placeholder);

            const input = container.querySelector('.Select__input');

            fireEvent.change(input!, { target: { value: 'abc' } });

            const optionElement1 = await findByText(option1.label);

            fireEvent.click(optionElement1);

            expect(dropdownElement).not.toHaveClass('show');
        });
    });

    describe('onClose callback', () => {
        const onClose = vi.fn();
        afterEach(() => onClose.mockReset());

        test('is called when an option is selected and `closeMenuOnSelect` is enabled', async () => {
            const { container, getByText, findByText } = render({
                closeMenuOnSelect: true,
                onClose,
            });

            const element = getByText(content);
            fireEvent.click(element);

            const input = container.querySelector('.Select__input');

            fireEvent.change(input!, { target: { value: 'abc' } });

            const optionElement1 = await findByText(option1.label);

            fireEvent.click(optionElement1);

            expect(onClose).toHaveBeenCalledTimes(1);
            expect(onClose).toHaveBeenCalledWith('select');
        });

        test('is called when clear is clicked and `closeMenuOnClear` is enabled', async () => {
            const { container, getByText } = render({
                closeMenuOnClear: true,
                isClearable: true,
                onClose,
                value: option1,
            });

            const element = getByText(content);
            fireEvent.click(element);
            const clearElement = container
                .getElementsByClassName('Select__clear-indicator')
                .item(0);

            expect(onClose).toHaveBeenCalledTimes(0);
            if (clearElement) fireEvent.mouseDown(clearElement);

            expect(onClose).toHaveBeenCalledTimes(1);
            expect(onClose).toHaveBeenCalledWith('select');
        });

        test('is called when the underlying dropdown is closed', async () => {
            const { container, getByText } = render({
                onClose,
            });

            const element = getByText(content);
            fireEvent.click(element);
            expect(onClose).toHaveBeenCalledTimes(0);

            fireEvent.click(container);
            expect(onClose).toHaveBeenCalledTimes(1);
            expect(onClose).toHaveBeenCalledWith('rootClose');
        });
    });
});
