import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import InfiniteScroll, {
    InfiniteScrollProps,
} from 'src/components/shared/infinite-scroll';

describe('<InfiniteScroll>', () => {
    const CONTENT = 'CONTENT';
    const fetchMore = jest.fn();

    const render = (props?: Partial<InfiniteScrollProps>) =>
        renderInAppContext(
            <div className="main-content" data-testid="main-content">
                <InfiniteScroll
                    fetchMore={fetchMore}
                    count={0}
                    loading={false}
                    {...props}
                >
                    <div>CONTENT</div>
                </InfiniteScroll>
            </div>
        );

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

        const mainContent = screen.getByTestId('main-content');
        if (!mainContent) throw new Error('MainContent not found');
        fireEvent.scroll(mainContent);
    };

    it('renders', () => {
        render({ count: 0, loading: false });
        expect(screen.getByText(CONTENT)).toBeDefined();
        expect(screen.getByTestId('main-content')).toBeDefined();
    });

    it('shows frc loading indicator if count is > 0', () => {
        render({ count: 100, loading: true });
        expect(screen.getByTestId('InfiniteScrollLoader')).toBeDefined();
    });

    it('does not fire fetchMore when loading', () => {
        renderAndScroll({ count: 0, loading: true });
        expect(fetchMore).not.toHaveBeenCalled();
    });

    it('does not fire fetchMore if count equals limit', () => {
        renderAndScroll({
            fetchMore,
            count: 200,
            totalLimit: 200,
            loading: false,
        });

        expect(fetchMore).not.toHaveBeenCalled();
    });

    it('fires fetchMore when scrolled', async () => {
        renderAndScroll({ count: 0, loading: false });
        await waitFor(() => expect(fetchMore).toHaveBeenCalled());
    });

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

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

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

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