import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import { render, fireEvent, waitForElement, waitForElementToBeRemoved } from '@testing-library/react';
import { Source } from 'src/definitions/Sources';
import {
    SOURCE_SAVES,
    SOURCE_SKIPS, SOURCE_STREAMS,
    SourceType,
    STORE_APPLE_MUSIC,
    STORE_SPOTIFY
} from 'src/constants/stores';
import { CLASSNAME_TABLE } from '../SourcesTable';
import SourcesStatus, {
    Props, TERM_TRIGGER_LABEL
} from '../SourcesStatus';

describe('<SourcesStatus>', () => {
    const sources: Source[] = [
        { storeName: 'Apple', storeId: STORE_APPLE_MUSIC, error: null },
        { storeName: 'Spotify', storeId: STORE_SPOTIFY, error: null }
    ];
    const sourceTypes: SourceType[] = [
        SOURCE_STREAMS,
        SOURCE_SKIPS,
        SOURCE_SAVES
    ];

    const defaultProps: Props = {
        sources,
        sourceTypes,
        id: 'TEST'
    };

    const renderMocked = (props: Partial<Props> = {}) =>
        render(<SourcesStatus {...{ ...defaultProps, ...props }} />);

    test('shows popover trigger', () => {
        const container = renderMocked();
        const label = container.getByText(TERM_TRIGGER_LABEL);

        expect(label).toBeVisible();
    });

    describe('when clicked', () => {
        test('toggles popover', async () => {
            const { container, getByText } = renderMocked();
            const label = getByText(TERM_TRIGGER_LABEL);

            fireEvent.click(label);
            const table = await waitForElement(() =>
                container.getElementsByClassName(CLASSNAME_TABLE).item(0));
            expect(table).toBeVisible();

            const removed = waitForElementToBeRemoved(() =>
                container.getElementsByClassName(CLASSNAME_TABLE).item(0));
            fireEvent.click(label);
            expect(await removed).toBe(true);
        });
    });

    describe('when escape key is pressed', () => {
        test('popup is hidden', async () => {
            const { container, getByText } = renderMocked();
            const label = getByText(TERM_TRIGGER_LABEL);

            fireEvent.click(label);
            const table = await waitForElement(() =>
                container.getElementsByClassName(CLASSNAME_TABLE).item(0));
            expect(table).toBeVisible();

            const removed = waitForElementToBeRemoved(() =>
                container.getElementsByClassName(CLASSNAME_TABLE).item(0));
            fireEvent.keyDown(container, { key: 'Esc', code: 27 });
            expect(await removed).toBe(true);
        });
    });

    describe('when click outside popup', () => {
        test('popup is hidden', async () => {
            const { container, getByText, getByTestId } = render(
                <div>
                    <div data-testid="outside-element">Outside</div>
                    <SourcesStatus {...{ ...defaultProps }} />
                </div>
            );
            const label = getByText(TERM_TRIGGER_LABEL);

            fireEvent.click(label);
            const table = await waitForElement(() =>
                container.getElementsByClassName(CLASSNAME_TABLE).item(0));
            expect(table).toBeVisible();

            const removed = waitForElementToBeRemoved(() =>
                container.getElementsByClassName(CLASSNAME_TABLE).item(0));
            getByTestId('outside-element').click();
            expect(await removed).toBe(true);
        });
    });

    describe('when mouse clicks inside popup', () => {
        test('popup is not hidden', async () => {
            const { container, getByText } = renderMocked();
            const label = getByText(TERM_TRIGGER_LABEL);

            fireEvent.click(label);
            const table = await waitForElement(() =>
                container.getElementsByClassName(CLASSNAME_TABLE).item(0));
            expect(table).toBeVisible();

            fireEvent.click(container);
            expect(table).toBeVisible();
        });
    });
});
