import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import { testComponent } from 'lib/test-utils/common';
import { PageContext } from '../../pageContext';
import { Popover, PopoverProps } from '../popover';

describe('<Popover>', () => {
    const pageClassName = 'page-class';

    const defaultProps: PopoverProps & { children: React.ReactElement } = {
        id: 'clickMe',
        testId: 'Popover-clickMe',
        content: <p>Im Popover-ed</p>,
        children: <strong>ClickMe</strong>,
    };

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

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

    testComponent(Popover);

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

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

    test('shows the popover content when clicking the element', async () => {
        const { findByText, getByTestId } = renderComponent();

        const popoverBase = getByTestId('Popover-clickMe');
        fireEvent.click(popoverBase);

        const popoverContent = await findByText('Im Popover-ed');
        expect(popoverContent).toBeInTheDocument();
    });

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

            const popoverContent = await findByText('Im Popover-ed');
            expect(popoverContent).toBeInTheDocument();
        });

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

            const popoverBase = getByTestId('Popover-clickMe');
            fireEvent.click(popoverBase);

            const popoverContent = queryByText('Im Popover-ed');
            expect(popoverContent).not.toBeInTheDocument();
        });

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

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

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

    describe('variant prop', () => {
        test('is set to `standard` by default', async () => {
            const { findByText, getByTestId } = renderComponent();

            const popoverBase = getByTestId('Popover-clickMe');
            fireEvent.click(popoverBase);

            const popoverContent = await findByText('Im Popover-ed');
            const container = popoverContent.closest('.PopoverContent');
            expect(container).toHaveClass('PopoverContent-standard');
        });

        test('is passed through correctly', async () => {
            const { findByText, getByTestId } = renderComponent({ variant: 'list' });

            const popoverBase = getByTestId('Popover-clickMe');
            fireEvent.click(popoverBase);

            const popoverContent = await findByText('Im Popover-ed');
            const container = popoverContent.closest('.PopoverContent');
            expect(container).toHaveClass('PopoverContent-list');
        });
    });

    describe('render prop for children', () => {
        test('passes isOpen state to render function', async () => {
            const { getByTestId, getByText } = renderComponent({
                children: ({ isOpen }) => <button>Trigger {isOpen ? 'Open' : 'Closed'}</button>,
            });

            const trigger = getByText('Trigger Closed');
            expect(trigger).toBeInTheDocument();

            const popoverBase = getByTestId('Popover-clickMe');
            fireEvent.click(popoverBase);

            expect(getByText('Trigger Open')).toBeInTheDocument();
        });

        test('passes controlled show state', async () => {
            const { getByText } = renderComponent({
                show: true,
                children: ({ isOpen }) => <button>Status: {isOpen ? 'Active' : 'Inactive'}</button>,
            });

            expect(getByText('Status: Active')).toBeInTheDocument();
        });
    });
});
