import React from 'react';
import { render, fireEvent, screen, within, waitFor } from '@testing-library/react';
import { testComponent } from 'lib/test-utils/common';
import { HelpTooltip, HelpTooltipProps } from '../helpTooltip';

describe('<HelpTooltip>', () => {
    const defaultProps: HelpTooltipProps = {
        message: 'Hello World',
        id: 'hello-world',
    };

    const renderComponent = (props: Partial<HelpTooltipProps> = {}, children?: JSX.Element) =>
        render(
            <HelpTooltip {...defaultProps} {...props}>
                {children}
            </HelpTooltip>
        );

    const openTooltip = async () => {
        const root = screen.getByTestId('HelpTooltip');
        fireEvent.mouseOver(root);
        await waitFor(() => expect(screen.queryByTestId('HelpTooltipOverlay')).toBeVisible());
    };

    testComponent(HelpTooltip);

    test('matches snapshot', () => {
        const { baseElement } = renderComponent();
        expect(baseElement).toMatchSnapshot();
    });

    test('has className', () => {
        const className = 'my-class';
        const { container } = renderComponent({ className });
        const root = container.querySelector('.HelpTooltip');
        expect(root).toBeVisible();
        expect(root).toHaveClass(className);
    });

    test('has testId', () => {
        const { getByTestId } = renderComponent();
        const root = getByTestId('HelpTooltip');
        expect(root).toBeVisible();
    });

    test('has customizable testId', () => {
        const testId = 'test';
        const { getByTestId } = renderComponent({ testId });
        const root = getByTestId(testId);
        expect(root).toBeVisible();
    });

    test('renders info icon', () => {
        const { container, getByTestId } = renderComponent();
        const icon = getByTestId('InfoGlyphIcon');
        expect(icon).toBeVisible();

        const root = container.querySelector('.HelpTooltip');
        expect(root).toHaveClass('with-icon');
    });

    describe('with children', () => {
        test('renders children', () => {
            const text = 'Custom content';
            const { getByText, queryByTestId } = renderComponent({}, <span>{text}</span>);

            expect(getByText(text)).toBeVisible();
            expect(queryByTestId('InfoGlyph')).toBeNull();
        });
    });

    describe('when opened', () => {
        test('matches snapshot', async () => {
            const { baseElement } = renderComponent();

            await openTooltip();
            expect(baseElement).toMatchSnapshot();
        });

        test('renders string messages', async () => {
            const message = 'Here is your help';
            const { getByText } = renderComponent({ message });

            await openTooltip();
            expect(getByText(message)).toBeVisible();
        });

        test('renders html messages', async () => {
            const text = 'Here is your help';
            const message = <div>{text}</div>;
            const { getByText } = renderComponent({ message });

            await openTooltip();
            expect(getByText(text)).toBeVisible();
        });

        describe('with "overlayType" set to "popover"', () => {
            test('renders popover overlay', async () => {
                const { baseElement } = renderComponent({
                    overlayType: 'popover',
                });

                await openTooltip();
                expect(baseElement.querySelector('.popover')).toBeVisible();
            });
        });

        describe('with "overlayClassName"', () => {
            test('renders overlay with class', async () => {
                const overlayClassName = 'my-class-name';
                const { baseElement } = renderComponent({ overlayClassName });

                await openTooltip();
                expect(baseElement.querySelector(`.${overlayClassName}`)).toBeVisible();
            });
        });

        describe('with empty message', () => {
            test('adds "with-empty-message" class name to overlay', async () => {
                const message = '';
                const { baseElement } = renderComponent({
                    message,
                });

                await openTooltip();

                const tooltip = baseElement.querySelector('.HelpTooltip-overlay');

                expect(tooltip).toHaveClass('with-empty-message');
            });
        });

        describe('with "container"', () => {
            test('renders overlay in specified element', async () => {
                const el = document.createElement('div');
                renderComponent({ container: el });

                const root = screen.getByTestId('HelpTooltip');
                fireEvent.mouseOver(root);

                expect(screen.queryByText('Hello World')).toBeNull();

                await waitFor(() => {
                    expect(within(el).getByText('Hello World')).toBeTruthy();
                });
            });
        });
    });
});
