import React from 'react';
import { fireEvent, render as renderDom } from '@testing-library/react';
import { testComponent } from 'lib/test-utils/common';
import { CTA_CLASS_NAME } from '../constants';
import { DropdownCTA } from '../dropdownCTA';
import { DropdownCTAProps } from '../types';

describe('<DropdownCTA>', () => {
    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<DropdownCTAProps>) =>
        renderDom(
            <DropdownCTA
                name={name}
                options={options}
                placeholder={placeholder}
                headerPlaceholder={content}
                {...props}
            >
                {props?.children}
            </DropdownCTA>
        );

    testComponent(DropdownCTA);

    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);
        const optionElement1 = await findByText(option1.label);
        const optionElement2 = await findByText(option2.label);

        expect(placeholderElement).toBeInTheDocument();
        expect(optionElement1).toBeInTheDocument();
        expect(optionElement2).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');

        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');

            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 { getByText, findByText } = render({
                closeMenuOnSelect: true,
                onClose,
            });

            const element = getByText(content);
            fireEvent.click(element);
            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,
                selectedValue: option1.value,
            });

            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');
        });
    });

    test('does not render filter when hideFilter is enabled', async () => {
        const { container } = render({ hideFilter: true });

        expect(container.getElementsByClassName(`${CTA_CLASS_NAME}-hide-filter`).length).toBe(1);
    });

    test('renders custom header button', async () => {
        const text = 'Some Custom Text';
        const { getByText, queryByText, findByText } = render({
            children: <>{text}</>,
        });

        const element = getByText(text);
        expect(element).toBeVisible();
        expect(queryByText(content)).toBeNull();

        fireEvent.click(element);

        const optionElement1 = await findByText(option2.label);
        expect(optionElement1).toBeInTheDocument();
    });
});
