import React from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { MAIN_CONTENT_CLASSNAME } from 'src/constants';
import InfiniteScroll, { InfiniteScrollProps, TESTID } from '../infiniteScroll';

describe('<InfiniteScroll>', () => {
    const CONTENT = 'CONTENT';

    const renderComponent = (props?: Partial<InfiniteScrollProps>) =>
        render(
            <div className={MAIN_CONTENT_CLASSNAME}>
                <InfiniteScroll
                    fetchMore={jest.fn()}
                    count={0}
                    loading={false}
                    {...props}
                >
                    <div>CONTENT</div>
                </InfiniteScroll>
            </div>
        );

    const renderAndScroll = (props?: Partial<InfiniteScrollProps>) => {
        const result = renderComponent(props);

        const mainContent = result.container
            .getElementsByClassName(MAIN_CONTENT_CLASSNAME)
            .item(0);
        if (!mainContent) throw new Error('MainContent not found');

        fireEvent.scroll(mainContent);

        return result;
    };

    test('renders wrapper and content component', () => {
        const { getByText, getByTestId } = renderComponent();
        expect(getByText(CONTENT)).toBeVisible();
        expect(getByTestId(TESTID)).toBeVisible();
    });

    test('shows frc loading indicator if count is > 0', () => {
        const { container } = renderComponent({ count: 100, loading: true });
        expect(
            container.getElementsByClassName('PageLoadingIndicator').length
        ).toBe(0);
        expect(
            container.getElementsByClassName('LoadingIndicator').length
        ).toBe(1);
    });

    test('fires fetchMore when scrolled', async () => {
        const fetchMore = jest.fn();
        renderAndScroll({ fetchMore, count: 0, loading: false });

        await waitFor(() => expect(fetchMore).toHaveBeenCalled());
    });

    test('does not fire fetchMore when loading', async () => {
        const fetchMore = jest.fn();
        renderAndScroll({ fetchMore, count: 0, loading: true });
        await waitFor(() => expect(fetchMore).not.toHaveBeenCalled());
    });

    test('does not fire fetchMore if count equals limit', async () => {
        const fetchMore = jest.fn();
        renderAndScroll({
            fetchMore,
            count: 200,
            totalLimit: 200,
            loading: true,
        });

        await waitFor(() => expect(fetchMore).not.toHaveBeenCalled());
    });

    test('fetchMore called with correct offset/limit', async () => {
        const limit = 100;
        const offset = 0;
        const fetchMore = jest.fn();
        renderAndScroll({
            fetchMore,
            count: offset,
            loadLimit: limit,
            loading: false,
        });

        await waitFor(() =>
            expect(fetchMore).toHaveBeenCalledWith(limit, offset)
        );
    });

    test('fetchMore limit does not go over totalLimit', async () => {
        const limit = 100;
        const totalLimit = 200;
        const offset = 190;
        const fetchMore = jest.fn();
        renderAndScroll({
            fetchMore,
            count: offset,
            loadLimit: limit,
            totalLimit,
            loading: false,
        });

        await waitFor(() =>
            expect(fetchMore).toHaveBeenCalledWith(totalLimit - offset, offset)
        );
    });
});
