import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import { range } from 'lodash';
import { render, RenderResult } from '@testing-library/react';
import { Source } from 'src/definitions/Sources';
import {
    STORE_APPLE_MUSIC,
    STORE_SPOTIFY,
    STORE_NAPSTER,
    STORE_AMAZON_MUSIC,
    SourceType,
    SOURCE_SAVES,
    SOURCE_SKIPS, SOURCE_STREAMS, SOURCE_DOWNLOADS, STORE_GOOGLE_PLAY,
} from 'src/constants/stores';
import SourcesStatusTable, {
    Props, hasType, MARKER_CLASSNAME_OK, MARKER_CLASSNAME_ERROR
} from '../SourcesTable';

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

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

    const testRowMarkers = (container: RenderResult, source: Source, classNames: string[]) => {
        const row = container.getByTestId(`store-${source.storeId}`);
        const cells = row.getElementsByTagName('td');
        let cellsWithMarkers = 0;

        range(cells.length).forEach(i => {
            const cell = cells.item(i);
            if (!cell) throw new Error(`Failed to find table cell at index: ${i}`);

            const type = cell.getAttribute('data-type');
            const markerShown = type && hasType(source, type);

            if (markerShown) {
                expect(cell.firstElementChild).toHaveClass('dot', 'dot-sm', classNames[cellsWithMarkers]);
                cellsWithMarkers += 1;
            } else
                expect(cell.firstElementChild).toBeNull();
        });

        expect(cellsWithMarkers).toEqual(classNames.length);
    };

    test('shows one row for each source', () => {
        const container = renderMocked();

        sources.forEach(source => {
            expect(container.getByText(source.storeName)).toBeVisible();
        });
    });

    test('renders a green marker for each OK source type', () => {
        const container = renderMocked();

        testRowMarkers(container, apple, [
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK
        ]);
        testRowMarkers(container, spotify, [
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK
        ]);
    });

    test('renders a red marker for each NON-OK source type', () => {
        const source1WithError = {
            storeName: 'Napster',
            storeId: STORE_NAPSTER,
            error: { code: 'iboom', types: ['streams'], message: null }
        };
        const source2WithError = {
            storeName: 'Amazon',
            storeId: STORE_AMAZON_MUSIC,
            error: { code: 'kaboom', types: ['streams'], message: null }
        };
        const source3WithError = {
            storeName: 'Google Play',
            storeId: STORE_GOOGLE_PLAY,
            error: { code: 'test_code', types: ['downloads'], message: null }
        };
        const spotifyWithSkipsError = {
            storeName: 'Spotify',
            storeId: STORE_SPOTIFY,
            error: { code: 'kaboom', types: ['skips_saves'], message: null }
        };
        const [sourceWithoutError] = sources;

        const container = renderMocked({
            sources: [
                sourceWithoutError,
                source1WithError,
                source2WithError,
                source3WithError,
                spotifyWithSkipsError
            ]
        });

        testRowMarkers(container, source1WithError, [
            MARKER_CLASSNAME_ERROR]);
        testRowMarkers(container, source2WithError, [
            MARKER_CLASSNAME_ERROR,
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK
        ]);
        testRowMarkers(container, source3WithError, [
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_ERROR]);
        testRowMarkers(container, sourceWithoutError, [
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_OK]);
        testRowMarkers(container, spotifyWithSkipsError, [
            MARKER_CLASSNAME_OK,
            MARKER_CLASSNAME_ERROR,
            MARKER_CLASSNAME_ERROR
        ]);
    });
});
