import '@testing-library/jest-dom/extend-expect';
import { fireEvent, act } from '@testing-library/react';
import renderWithProvider from 'lib/testing/provider';
import { mockQuery } from 'lib/testing/mocks';
import * as queries from 'src/queries';
import { DEFAULT_PLAYLISTS_TOTAL_COUNT, DEFAULT_PLAYLISTS_COUNT } from 'src/constants/playlists';
import { SoundRecordingPlaylistRecords } from 'src/selectors';
import { TERM_TRIGGER_LABEL as DATASOURCES_TERM_TRIGGER } from 'src/components/sourcesStatus/SourcesStatus';
import TopPlaylists, { TERM_HEADER, CLASSNAME } from '../TopPlaylists';
import { TEST_ID as PLAYLIST_TEST_ID } from '../topPlaylist/TopPlaylist';

type BatchPlaylistsQueryResult = {
    loading: boolean;
    data: SoundRecordingPlaylistRecords[],
    error: Error | undefined;
    count: number;
    showCount: (count?: number) => void;
};

const DUMMY_PLAYLIST = {
    playlistName: 'test',
    playlistUrl: 'https://www.example.org',
    playlistImage: 'https://www.example.org/example.jpg'
};

describe('<TopPlaylists>', () => {
    const selectedSongIds = ['CODE1', 'CODE2'];
    let queryData: BatchPlaylistsQueryResult;

    const renderMocked = async () => {
        const container = await renderWithProvider(TopPlaylists, {
            filter: { selectedSongIds },
            mocks: selectedSongIds.map(isrc =>
                mockQuery('SoundRecordingMetadataQuery', {
                    variables: { isrc }
                }))
        });

        return container;
    };

    beforeEach(() => {
        queryData = {
            loading: false,
            data: [{
                isrc: 'test_ISRC',
                name: 'Test Name',
                playlists: Array(6).fill(DUMMY_PLAYLIST),
                sources: [],
                totalStreams: 0,
            }],
            error: undefined,
            count: 0,
            showCount: jest.fn()
        };
    });

    afterEach(() => {
        jest.restoreAllMocks();
    });

    test('renders TopPlaylists', async () => {
        const component = await renderMocked();
        const { container } = component;
        const header = component.getByText(TERM_HEADER);
        const content = container.getElementsByClassName(CLASSNAME);
        const showMore = container.getElementsByClassName(`${CLASSNAME}-show-more`);
        expect(header).toBeVisible();
        expect(showMore.item(0)).toBeVisible();
        expect(content.length).toBe(1);
    });

    test('renders two playlists', async () => {
        const container = await renderMocked();

        const playlistItems = container.getAllByTestId(PLAYLIST_TEST_ID);
        expect(playlistItems.length).toBe(2);
    });

    test('it shows sources', async () => {
        const container = await renderMocked();

        const sourcePopoverTrigger = container.getByText(DATASOURCES_TERM_TRIGGER);
        expect(sourcePopoverTrigger).toBeVisible();
    });

    test('calls handleMore handler', async () => {
        jest.spyOn(queries, 'useBatchPlaylistsQuery').mockImplementation(() => queryData);
        const container = await renderMocked();
        const showMoreButton = container.getByText(/show.more/);
        act(() => {
            fireEvent.click(showMoreButton);
        });

        expect(queryData.showCount).toHaveBeenCalledWith(DEFAULT_PLAYLISTS_TOTAL_COUNT);
    });


    test('disables handleMore if <= 5 playlists', async () => {
        jest.spyOn(queries, 'useBatchPlaylistsQuery').mockImplementation(() => ({
            ...queryData,
            data: queryData.data.map(data => ({
                ...data,
                playlists: []
            }))
        }));
        const container = await renderMocked();
        const showMoreButton = container.getByText(/show.more/);
        act(() => {
            fireEvent.click(showMoreButton);
        });

        expect(showMoreButton).toBeDisabled();
        expect(queryData.showCount).not.toHaveBeenCalled();
    });

    test('calls handleLess handler', async () => {
        jest.spyOn(queries, 'useBatchPlaylistsQuery').mockImplementation(() => queryData);
        const container = await renderMocked();
        let showMoreButton = container.getByText(/show.more/);
        act(() => {
            fireEvent.click(showMoreButton);
        });

        showMoreButton = container.getByText(/show.less/);
        act(() => {
            fireEvent.click(showMoreButton);
        });

        expect(queryData.showCount).toHaveBeenCalledWith(DEFAULT_PLAYLISTS_COUNT);
    });
});
