import React from 'react';
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
import { testComponent } from 'lib/test-utils/common';
import { CloseGlyph } from '../../glyphs';
import { PageContext } from '../../pageContext';
import { Tooltip, TooltipProps } from '../tooltip';

describe('<Tooltip>', () => {
    const pageClassName = 'page-class';
    const defaultProps: TooltipProps & { children: React.ReactElement } = {
        id: 'hoverMe',
        testId: 'Tooltip-hoverMe',
        message: 'Hey Beautiful',
        children: <strong>hover me</strong>,
    };

    const renderComponent = (customProps?: Partial<TooltipProps>) => {
        const props = { ...defaultProps, ...customProps };

        return render(<Tooltip {...props} />, {
            wrapper: ({ children }) => (
                <PageContext.Provider value={{ className: pageClassName }}>
                    {children}
                </PageContext.Provider>
            ),
        });
    };

    testComponent(Tooltip);

    test('renders element in the DOM correctly', () => {
        const { container } = renderComponent();

        expect(container).toBeInTheDocument();
    });

    test('shows the tooltip message when hovering the element', async () => {
        const { findByText, getByTestId } = renderComponent();

        const tooltipBase = getByTestId('Tooltip-hoverMe');
        fireEvent.mouseOver(tooltipBase);

        const tooltipPopover = await findByText('Hey Beautiful');
        expect(tooltipPopover).toBeInTheDocument();
    });

    test('when message is ReactElement', async () => {
        const { findByText, getByTestId } = renderComponent({
            message: (
                <>
                    <CloseGlyph />
                    <span>Hey Beautiful</span>
                </>
            ),
        });

        const tooltipBase = getByTestId('Tooltip-hoverMe');
        fireEvent.mouseOver(tooltipBase);

        const tooltipPopoverText = await findByText('Hey Beautiful');
        const tooltipPopoverIcon = getByTestId('CloseGlyphIcon');
        expect(tooltipPopoverText).toBeInTheDocument();
        expect(tooltipPopoverIcon).toBeInTheDocument();
    });

    describe('when show is set', () => {
        test('shows the tooltip content without hover when show is true', async () => {
            const { findByText } = renderComponent({ show: true });

            const tooltipContent = await findByText('Hey Beautiful');
            expect(tooltipContent).toBeInTheDocument();
        });

        test('does not show the tooltip content when show is false even on hover', async () => {
            const { queryByText, getByTestId } = renderComponent({
                show: false,
            });

            const tooltipBase = getByTestId('Tooltip-hoverMe');
            fireEvent.mouseOver(tooltipBase);

            const tooltipContent = queryByText('Hey Beautiful');
            expect(tooltipContent).not.toBeInTheDocument();
        });

        test('applies className from page context', async () => {
            renderComponent({ show: true });

            await waitFor(() => {
                const portal = document.querySelector(`.${pageClassName}.TooltipOverlay`);

                expect(portal).toBeInTheDocument();
            });
        });
    });

    describe('with "contentPrivacy"', () => {
        test('adds "data-dd-privacy" attribute', async () => {
            const { findByText } = renderComponent({
                show: true,
                contentPrivacy: 'hidden',
            });

            const tooltipElement = (await findByText(defaultProps.message as string)).closest(
                '.tooltip'
            );

            expect(tooltipElement).toHaveAttribute('data-dd-privacy', 'hidden');
        });
    });

    describe('popperConfig', () => {
        test('is passed to tooltip', async () => {
            const onFirstUpdate = vitest.fn();
            renderComponent({ popperConfig: { onFirstUpdate } });

            const tooltipBase = screen.getByTestId('Tooltip-hoverMe');
            fireEvent.mouseOver(tooltipBase);

            const tooltipPopover = await screen.findByText('Hey Beautiful');
            expect(tooltipPopover).toBeInTheDocument();

            expect(onFirstUpdate).toHaveBeenCalledTimes(1);
        });
    });

    describe('with custom prop maxWidth', () => {
        test('applies custom maxWidth', () => {
            const customWidth = 400;
            renderComponent({
                show: true,
                maxWidth: customWidth,
            });

            const element = document.querySelector(`.TooltipOverlay`);

            expect(element).toHaveStyle('--tooltip-width: 400px;');
        });
    });

    describe('with custom prop textAlign', () => {
        test('applies left textAlign', () => {
            renderComponent({
                show: true,
                textAlign: 'left',
            });

            const element = document.querySelector(`.TooltipOverlay`);

            expect(element).toHaveStyle('--tooltip-text-align: left;');
        });

        test('omits textAlign style when not passed', () => {
            renderComponent({
                show: true,
            });

            const element = document.querySelector(`.TooltipOverlay`) as HTMLElement;

            expect(element?.style.getPropertyValue('--tooltip-text-align')).toBe('');
        });
    });

    describe('overlayClassName', () => {
        test('applies custom class to TooltipOverlay', () => {
            renderComponent({
                show: true,
                overlayClassName: 'custom-overlay-class',
            });

            const element = document.querySelector('.TooltipOverlay');

            expect(element).toHaveClass('custom-overlay-class');
        });

        test('does not add extra class when not passed', () => {
            renderComponent({
                show: true,
            });

            const element = document.querySelector('.TooltipOverlay');

            expect(element).toHaveClass('TooltipOverlay', pageClassName);
            expect(element).not.toHaveClass('custom-overlay-class');
        });
    });
});
